first commit

This commit is contained in:
Mauve
2026-09-08 17:12:13 +08:00
commit cc4739711c
274 changed files with 14961 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
/crm_runtime/logs/
/target/
/.idea/
/.vscode/
+165
View File
@@ -0,0 +1,165 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mgm</groupId>
<artifactId>MCRMApiGateway</artifactId>
<version>1.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>MCRMApiGateway</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.7</version>
<relativePath />
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>21</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.50</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.18.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.14.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.11</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
<mainClass>com.mgm.mcrm.apigateway.CRMApiGatewayApplication</mainClass>
<!-- <executable>true</executable>-->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>license-maven-plugin</artifactId>
<version>2.7.0</version>
<configuration>
<excludedLicenses>
<excludedLicense>EPL-1.0</excludedLicense>
<excludedLicense>LGPL-2.1</excludedLicense>
</excludedLicenses>
</configuration>
</plugin>
</plugins>
</build>
<description>MCRM API Gateway</description>
</project>
@@ -0,0 +1,27 @@
package com.mgm.mcrm.apigateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@EntityScan(basePackages="com.mgm.mcrm.apigateway")
@ComponentScan(basePackages="com.mgm.mcrm.apigateway")
@EnableTransactionManagement
@ServletComponentScan
@EnableScheduling
@EnableAsync
@EnableJms
public class CRMApiGatewayApplication {
public static void main( String[] args ) {
SpringApplication.run(CRMApiGatewayApplication.class, args);
}
}
@@ -0,0 +1,19 @@
package com.mgm.mcrm.apigateway.allotment.dtos.request;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class BlockCodeChannelDto {
private Long blockCodeId;
private String code;
private String category;
private LocalDateTime startDate;
private LocalDateTime endDate;
private String sourceName;
private String dlBlockId;
private Integer channelTotal;
private Integer available;
private Integer pickedUp;
}
@@ -0,0 +1,14 @@
package com.mgm.mcrm.apigateway.allotment.dtos.request;
import lombok.Data;
import java.time.LocalDate;
@Data
public class DlAllotmentUpdateRequest {
private Long roomId;
private Long blockCodeId;
private Long propertyId;
private LocalDate calendarDate;
private String updateSource;
}
@@ -0,0 +1,30 @@
package com.mgm.mcrm.apigateway.allotment.models;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name="cfg_app_channel_daylight")
@IdClass(CfgAppChannelDaylightKey.class)
public class CfgAppChannelDaylight implements Serializable {
@Id
@Column(name="criteria_id")
private Long criteriaId;
@Id
@Column(name="block_code_id")
private Long blockCodeId;
@Column(name="created_at")
private LocalDateTime createdAt;
@Column(name="created_src")
private String createdSource;
@Column(name="channel_total")
private Integer channelTotal;
@Column(name="picked_up")
private Integer pickedUp;
@Column(name="available")
private Integer available;
}
@@ -0,0 +1,29 @@
package com.mgm.mcrm.apigateway.allotment.models;
import lombok.Data;
import java.io.Serializable;
import java.util.Objects;
@Data
public class CfgAppChannelDaylightKey implements Serializable{
private Long criteriaId;
private Long blockCodeId;
@Override
public boolean equals(Object o) {
if(o instanceof CfgAppChannelDaylightKey key)
{
return Objects.equals(this.criteriaId, key.getCriteriaId()) &&
Objects.equals(this.blockCodeId, key.getBlockCodeId());
}
return false ;
}
@Override
public int hashCode() {
return 1;
}
}
@@ -0,0 +1,61 @@
package com.mgm.mcrm.apigateway.allotment.models;
import jakarta.persistence.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name="cfg_daylight_roomtype_allotment")
public class CfgDlRoomTypeAllotment {
@Id
@Column(name = "allotment_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long allotmentId;
@Column(name="allotment_date")
private String allotmentDate;
@Column(name="dl_room_type_id")
private String daylightRoomTypeId;
@Column(name="dl_property_id")
private String daylightPropertyId;
@Column(name="dl_block_code_id")
private String daylightBlockCodeId;
@Column(name="property_id")
private Long propertyId;
@Column(name="room_type_id")
private Long roomTypeId;
@Column(name="block_code_id")
private Long blockCodeId;
@Column(name="total_rooms")
private Integer totalRooms;
@Column(name="sell_limit")
private Integer sellLimit;
@Column(name="over_booking_limit")
private Integer overBookingLimit;
@Column(name="all_deduct")
private Integer allDeduct;
@Column(name="all_non_deduct")
private Integer allNonDeduct;
@Column(name="created_at")
private LocalDateTime createdAt;
@Column(name="updated_at")
private LocalDateTime updatedAt;
@Column(name="updated_source")
private String updateSource;
}
@@ -0,0 +1,63 @@
package com.mgm.mcrm.apigateway.allotment.models;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.mgm.mcrm.apigateway.allotment.dtos.request.BlockCodeChannelDto;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
@Data
@Entity
@Table(name = "cfg_room_criterias_daylight")
public class CfgRoomCriteriasDaylight implements Serializable {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "property_id")
private Long propertyId;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "book_date")
private LocalDateTime bookDate;
@Column(name = "room_id")
private Long roomId;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Column(name = "updated_by")
private String updatedBy;
@Column(name = "is_waitlist")
private Integer isWaitlist;
@Column(name = "sharer")
private Integer sharer;
@Column(name = "dow")
private Integer bookDow;
@Transient
private List<BlockCodeChannelDto> blockCodeChannels;
@Column(name = "rate")
private Integer rate;
@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "criteria_id", insertable = false, updatable = false)
private Set<CfgAppChannelDaylight> channels;
}
@@ -0,0 +1,13 @@
package com.mgm.mcrm.apigateway.allotment.repositories;
import com.mgm.mcrm.apigateway.allotment.models.CfgAppChannelDaylight;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface AppChannelDaylightDao extends JpaRepository<CfgAppChannelDaylight, String> {
CfgAppChannelDaylight findByCriteriaIdAndBlockCodeId(Long criteriaId, Long blockCodeId);
List<CfgAppChannelDaylight> findAllByCriteriaIdAndBlockCodeId(Long allotmentId, Long blockCodeId);
}
@@ -0,0 +1,30 @@
package com.mgm.mcrm.apigateway.allotment.repositories;
import com.mgm.mcrm.apigateway.allotment.models.CfgDlRoomTypeAllotment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface DaylightRoomTypeAllotmentDao extends JpaRepository<CfgDlRoomTypeAllotment, Long> {
@Query(value="select allot from CfgDlRoomTypeAllotment allot where daylightPropertyId=?1 and daylightRoomTypeId=?2 and daylightBlockCodeId=?3 and allotmentDate=?4 ")
List<CfgDlRoomTypeAllotment> queryAllotmentByRoomTypeAndDate(String dlPropertyId, String dlRoomTypeId, String dlBlockCodeId, String checkDateVal);
interface DaylightBlockCodeAllotmentSum{
public String getCalendarDate();
public Integer getChannelTotal();
public Integer getPickedUp();
public Integer getAvailable();
}
@Query(value = "select ?1 as calendarDate, sum(total_rooms) as channelTotal, sum(all_deduct) as pickedUp, sum(all_non_deduct) as available " +
" from cfg_daylight_roomtype_allotment " +
" where allotment_date=?1 and property_id =?2 and block_code_id =?4 and room_type_id in " +
" (select room_type_id from cfg_rooms_room_types where room_id =?3 )", nativeQuery = true)
DaylightBlockCodeAllotmentSum countRoomTypeAllotmentByBlockCode(
String calendarDate,
Long propertyId,
Long roomId,
Long blockCodeId);
}
@@ -0,0 +1,23 @@
package com.mgm.mcrm.apigateway.allotment.repositories;
import com.mgm.mcrm.apigateway.allotment.models.CfgRoomCriteriasDaylight;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import java.time.LocalDateTime;
import java.util.List;
public interface RoomCriteriaDaylightDao extends JpaRepository<CfgRoomCriteriasDaylight, Long> {
CfgRoomCriteriasDaylight findById(long id);
List<CfgRoomCriteriasDaylight> findAll(Specification<CfgRoomCriteriasDaylight> spec, Sort sort);
List<CfgRoomCriteriasDaylight> findAll(Specification<CfgRoomCriteriasDaylight> spec);
Page<CfgRoomCriteriasDaylight> findAll(Specification<CfgRoomCriteriasDaylight> spec, Pageable pageable);
List<CfgRoomCriteriasDaylight> findByRoomIdAndPropertyIdAndBookDate(Long roomId, Long propertyId, LocalDateTime bookDate);
}
@@ -0,0 +1,200 @@
package com.mgm.mcrm.apigateway.allotment.services;
import com.mgm.mcrm.apigateway.allotment.dtos.request.DlAllotmentUpdateRequest;
import com.mgm.mcrm.apigateway.allotment.models.CfgAppChannelDaylight;
import com.mgm.mcrm.apigateway.allotment.models.CfgDlRoomTypeAllotment;
import com.mgm.mcrm.apigateway.allotment.models.CfgRoomCriteriasDaylight;
import com.mgm.mcrm.apigateway.allotment.repositories.AppChannelDaylightDao;
import com.mgm.mcrm.apigateway.allotment.repositories.DaylightRoomTypeAllotmentDao;
import com.mgm.mcrm.apigateway.allotment.repositories.RoomCriteriaDaylightDao;
import com.mgm.mcrm.apigateway.basesetting.mapping.models.CfgBlockCodes;
import com.mgm.mcrm.apigateway.basesetting.mapping.repositories.BlockCodeDao;
import com.mgm.mcrm.apigateway.basesetting.mapping.repositories.BlockDao;
import com.mgm.mcrm.apigateway.basesetting.property.models.CfgProperties;
import com.mgm.mcrm.apigateway.basesetting.property.repositories.PropertyDao;
import com.mgm.mcrm.apigateway.basesetting.room.models.CfgRoomTypes;
import com.mgm.mcrm.apigateway.basesetting.room.repositories.RoomDao;
import com.mgm.mcrm.apigateway.basesetting.room.repositories.RoomTypeDao;
import com.mgm.mcrm.apigateway.common.utils.LogUtil;
import com.mgm.mcrm.apigateway.daylight.webhook.dtos.room.common.RoomCounterEntity;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
@Service
public class RoomCriteriaDaylightService {
@Resource
private RoomCriteriaDaylightDao criteriaDaylightDao;
@Resource
private AppChannelDaylightDao appChannelDaylightDao;
@Resource
private PropertyDao propertyDao;
@Resource
private RoomDao roomDao;
@Resource
private BlockDao blockDao;
@Resource
private RoomTypeDao roomTypeDao;
@Resource
private BlockCodeDao blockCodeDao;
@Resource
private DaylightRoomTypeAllotmentDao daylightRoomTypeAllotmentDao;
public void processDaylightRoomTypeAllotmentUpdate(String updateSource, String dlPropertyId, String dlRoomTypeId, String dlBlockCodeId, String fromDate, String toDate, RoomCounterEntity roomCounter) {
if (StringUtils.isNotBlank(fromDate)) {
Long propertyId = null;
Long roomTypeId = null;
Long blockCodeId = null;
Long roomId = null;
CfgProperties cfgProperty = propertyDao.findByDlPropertyId(dlPropertyId);
if (cfgProperty != null) {
propertyId = cfgProperty.getId();
} else {
LogUtil.warn(RoomCriteriaDaylightService.class, "[" + updateSource + "]No property config match with daylight ID[" + dlPropertyId + "]");
}
CfgRoomTypes cfgRoomType = roomTypeDao.findByDlRoomTypeId(dlRoomTypeId);
if (propertyId!=null && cfgRoomType != null) {
roomTypeId = cfgRoomType.getId();
roomId = roomDao.queryPropertyRoomIdByRoomTypeId(propertyId, roomTypeId);
if(roomId==null){
LogUtil.warn(RoomCriteriaDaylightService.class, "[" + updateSource + "]No Room Category(RoomId) config match with room type ID[" + roomTypeId + "]");
}
} else {
LogUtil.warn(RoomCriteriaDaylightService.class, "[" + updateSource + "]No Room Type config match with daylight ID[" + dlRoomTypeId + "]");
}
if (StringUtils.isNotBlank(dlBlockCodeId)) {
CfgBlockCodes cfgBlockCode = blockCodeDao.findByDlBlockId(dlBlockCodeId);
if (cfgBlockCode != null) {
blockCodeId = cfgBlockCode.getId();
}else{
LogUtil.warn(RoomCriteriaDaylightService.class, "[" + updateSource + "]No Block code config match with daylight ID[" + dlBlockCodeId + "]");
}
}
LocalDate allotmentDate = LocalDate.parse(fromDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDate endDate = null;
if (StringUtils.isNotBlank(toDate)) {
endDate = LocalDate.parse(toDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
} else {
endDate = allotmentDate.plusDays(1);
}
List<DlAllotmentUpdateRequest> updateAllotmentRequests = new ArrayList<DlAllotmentUpdateRequest>();
while (allotmentDate.isBefore(endDate)) {
String checkDateVal = allotmentDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
CfgDlRoomTypeAllotment matchAllotment = null;
List<CfgDlRoomTypeAllotment> roomAllotments = daylightRoomTypeAllotmentDao.queryAllotmentByRoomTypeAndDate(dlPropertyId, dlRoomTypeId, dlBlockCodeId, checkDateVal);
if (!roomAllotments.isEmpty()) {
matchAllotment = roomAllotments.get(0);
//-- Keep only one allotment for check date and room type
for (int i = 1; i < roomAllotments.size(); i++) {
daylightRoomTypeAllotmentDao.delete(roomAllotments.get(i));
}
}
if (matchAllotment == null) {
matchAllotment = new CfgDlRoomTypeAllotment();
matchAllotment.setAllotmentDate(checkDateVal);
matchAllotment.setDaylightPropertyId(dlPropertyId);
matchAllotment.setDaylightRoomTypeId(dlRoomTypeId);
matchAllotment.setDaylightBlockCodeId(dlBlockCodeId);
matchAllotment.setPropertyId(propertyId);
matchAllotment.setRoomTypeId(roomTypeId);
matchAllotment.setBlockCodeId(blockCodeId);
matchAllotment.setCreatedAt(LocalDateTime.now());
}
matchAllotment.setTotalRooms(roomCounter.getTotalRooms());
matchAllotment.setSellLimit(roomCounter.getSellLimit());
matchAllotment.setOverBookingLimit(roomCounter.getOverbookingLimit());
matchAllotment.setAllDeduct(roomCounter.getAllDeduct());
matchAllotment.setAllNonDeduct(roomCounter.getAllNonDeduct());
matchAllotment.setUpdatedAt(LocalDateTime.now());
matchAllotment.setUpdateSource(updateSource);
daylightRoomTypeAllotmentDao.save(matchAllotment);
//--Create update request to sync daylight allotment data
if(roomId !=null && blockCodeId!=null){
DlAllotmentUpdateRequest syncRequest = new DlAllotmentUpdateRequest();
syncRequest.setPropertyId(propertyId);
syncRequest.setBlockCodeId(blockCodeId);
syncRequest.setRoomId(roomId);
syncRequest.setCalendarDate(allotmentDate);
syncRequest.setUpdateSource("Daylight Webhook");
updateAllotmentRequests.add(syncRequest);
}
//--
allotmentDate = allotmentDate.plusDays(1);
}
if(!updateAllotmentRequests.isEmpty()){
for(DlAllotmentUpdateRequest syncRequest:updateAllotmentRequests){
this.calculateDaylightAllotment(syncRequest);
}
}
}
}
public void calculateDaylightAllotment(DlAllotmentUpdateRequest syncRequest) {
if(syncRequest!=null){
CfgRoomCriteriasDaylight roomAllotment = null;
List<CfgRoomCriteriasDaylight> roomCriterias = criteriaDaylightDao.findByRoomIdAndPropertyIdAndBookDate(
syncRequest.getRoomId(),
syncRequest.getPropertyId(),
syncRequest.getCalendarDate().atStartOfDay()
);
if(!roomCriterias.isEmpty()){
roomAllotment = roomCriterias.get(0);
if(roomCriterias.size()>1){
//-- Remove duplicated records if has
for(int i=1;i<roomCriterias.size();i++){
criteriaDaylightDao.delete(roomCriterias.get(i));
}
}
}
LocalDateTime currentTime = LocalDateTime.now();
if(roomAllotment==null){
roomAllotment = new CfgRoomCriteriasDaylight();
roomAllotment.setPropertyId(syncRequest.getPropertyId());
roomAllotment.setBookDate(syncRequest.getCalendarDate().atStartOfDay());
roomAllotment.setRoomId(syncRequest.getRoomId());
roomAllotment.setRate(0);
roomAllotment.setIsWaitlist(0);
roomAllotment.setSharer(0);
roomAllotment.setCreatedAt(currentTime);
roomAllotment.setUpdatedAt(currentTime);
roomAllotment.setBookDow(roomAllotment.getBookDate().getDayOfWeek().getValue());
criteriaDaylightDao.save(roomAllotment);
}
Long allotmentId = roomAllotment.getId();
//--
DaylightRoomTypeAllotmentDao.DaylightBlockCodeAllotmentSum roomAllotmentSum = daylightRoomTypeAllotmentDao.countRoomTypeAllotmentByBlockCode(
syncRequest.getCalendarDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
syncRequest.getPropertyId(),
syncRequest.getRoomId(),
syncRequest.getBlockCodeId()
);
CfgAppChannelDaylight appChannel=null;
List<CfgAppChannelDaylight> existAppChannels = appChannelDaylightDao.findAllByCriteriaIdAndBlockCodeId(allotmentId,syncRequest.getBlockCodeId());
if(!existAppChannels.isEmpty()){
appChannel = existAppChannels.get(0);
for(int i=1;i<existAppChannels.size();i++){
appChannelDaylightDao.delete(existAppChannels.get(i));
}
}
if(appChannel==null){
appChannel = new CfgAppChannelDaylight();
appChannel.setCriteriaId(allotmentId);
appChannel.setBlockCodeId(syncRequest.getBlockCodeId());
appChannel.setCreatedAt(LocalDateTime.now());
appChannel.setCreatedSource(syncRequest.getUpdateSource());
}
appChannel.setChannelTotal(roomAllotmentSum.getChannelTotal());
appChannel.setPickedUp(roomAllotmentSum.getPickedUp());
appChannel.setAvailable(roomAllotmentSum.getAvailable());
appChannelDaylightDao.save(appChannel);
}
}
}
@@ -0,0 +1,21 @@
package com.mgm.mcrm.apigateway.appsetting.models;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
@Data
@Entity
@Table(name="cfg_settings")
public class CfgSettings {
@Id
@Column(name="keys")
private String keys;
@Column(name="key_values")
private String keyValues;
}
@@ -0,0 +1,26 @@
package com.mgm.mcrm.apigateway.appsetting.models;
import java.io.Serializable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import lombok.Data;
@Data
@Entity
@Table(name="sys_settings")
public class SysSetting {
@Id
@Column(name="setting_key")
private String settingKey;
@Column(name="setting_value")
private String settingValue;
@Transient
private boolean internalNetwork=false;
}
@@ -0,0 +1,10 @@
package com.mgm.mcrm.apigateway.appsetting.repositories;
import com.mgm.mcrm.apigateway.appsetting.models.CfgSettings;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface SettingDao extends JpaRepository<CfgSettings, String> {
@Query(value = "select * from cfg_settings with (nolock) where keys = ?1",nativeQuery=true)
CfgSettings getByKeys(String keys);
}
@@ -0,0 +1,19 @@
package com.mgm.mcrm.apigateway.appsetting.repositories;
import java.util.List;
import com.mgm.mcrm.apigateway.appsetting.models.SysSetting;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface SysSettingDao extends JpaRepository<SysSetting, String> {
@Query(value="select * from sys_settings where setting_key=?1",nativeQuery=true)
SysSetting getBySettingKey(String key);
List<SysSetting> findAll(Specification<SysSetting> spec,Sort sort);
List<SysSetting> findAll(Specification<SysSetting> spec);
}
@@ -0,0 +1,28 @@
package com.mgm.mcrm.apigateway.appsetting.services;
import java.util.List;
import com.mgm.mcrm.apigateway.appsetting.models.CfgSettings;
import com.mgm.mcrm.apigateway.appsetting.repositories.SettingDao;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class SettingService {
@Resource
private SettingDao settingDao;
public CfgSettings getSettingByKey(String key) {
CfgSettings setting = null;
setting = settingDao.getByKeys(key);
return setting;
}
public List<CfgSettings> getSysSettingsAll() {
return settingDao.findAll();
}
}
@@ -0,0 +1,32 @@
package com.mgm.mcrm.apigateway.appsetting.services;
import java.util.List;
import com.mgm.mcrm.apigateway.appsetting.models.SysSetting;
import com.mgm.mcrm.apigateway.appsetting.repositories.SysSettingDao;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class SysSettingService {
@Resource
private SysSettingDao sysSettingDao;
public SysSetting getSysSettingByKey(String key) {
SysSetting sysSetting = null;
sysSetting = sysSettingDao.getBySettingKey(key);
return sysSetting;
}
public List<SysSetting> getSysSettingsAll() {
List<SysSetting> list = sysSettingDao.findAll();
return list;
}
public boolean isMockReplicate() {
SysSetting sysSetting = null;
sysSetting = sysSettingDao.getBySettingKey("APP_MOCK_REPLICATE");
return "1".equals(sysSetting.getSettingValue());
}
}
@@ -0,0 +1,45 @@
package com.mgm.mcrm.apigateway.basesetting.mapping.models;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Entity
@Table(name="cfg_block_codes")
@Data
public class CfgBlockCodes implements Serializable {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="block_id")
private Long blockId;
@Column(name="code")
private String code;
@Column(name = "category")
private String category;
@Column(name="created_at")
private LocalDateTime createdAt;
@Column(name="created_by")
private String createdBy;
@Column(name="updated_at")
private LocalDateTime updatedAt;
@Column(name="updated_by")
private String updatedBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
@Column(name="start_date")
private LocalDateTime startDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
@Column(name="end_date")
private LocalDateTime endDate;
@Column(name="sourceName")
private String sourceName;
@Column(name = "dl_block_id")
private String dlBlockId;
}
@@ -0,0 +1,35 @@
package com.mgm.mcrm.apigateway.basesetting.mapping.models;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Entity
@Table(name="cfg_blocks")
@Data
public class CfgBlocks implements Serializable {
//fields in table
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="name")
private String name;
@Column(name="created_at")
private LocalDateTime createdAt;
@Column(name="created_by")
private String createdBy;
@Column(name="updated_at")
private LocalDateTime updatedAt;
@Column(name="updated_by")
private String updatedBy;
@Transient
private Integer appChannel;
@Transient
private Integer available;
@Transient
private Integer pickedUp;
}
@@ -0,0 +1,29 @@
package com.mgm.mcrm.apigateway.basesetting.mapping.models;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "cfg_booking_types")
public class CfgBookingTypes implements Serializable {
//fields in table
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Column(name = "updated_by")
private String updatedBy;
}
@@ -0,0 +1,115 @@
package com.mgm.mcrm.apigateway.basesetting.mapping.models;
import com.mgm.mcrm.apigateway.basesetting.property.models.CfgProperties;
import com.mgm.mcrm.apigateway.basesetting.room.models.CfgRoomTypes;
import com.mgm.mcrm.apigateway.basesetting.team.models.CfgSections;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Set;
@Entity
@Table(name = "view_daylight")
@NamedEntityGraph(
name = "graph.DaylightMapping.fulldetails",
attributeNodes = {
@NamedAttributeNode("section"),
@NamedAttributeNode("property"),
@NamedAttributeNode("bookingType"),
@NamedAttributeNode("rateCode"),
@NamedAttributeNode("sourceCode"),
@NamedAttributeNode("marketCode"),
@NamedAttributeNode("daylightRoomType")
}
)
@Data
public class CfgDaylightView implements Serializable {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "section_id")
private Long sectionId;
@Column(name = "property_id")
private Long propertyId;
@Column(name = "booking_type_id")
private Long bookingTypeId;
@Column(name = "rate_code_id")
private Long rateCodeId;
@Column(name = "source_code_id")
private Long sourceCodeId;
@Column(name = "market_code_id")
private Long marketCodeId;
@Column(name = "block_code_id")
private Long blockCodeId;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Column(name = "updated_by")
private String updatedBy;
@Column(name = "block_code_name")
private String blockCodeName;
@Column(name = "start_date")
private LocalDateTime startDate;
@Column(name = "end_date")
private LocalDateTime endDate;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "section_id", insertable = false, updatable = false)
private CfgSections section;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "property_id", insertable = false, updatable = false)
private CfgProperties property;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "booking_type_id", insertable = false, updatable = false)
private CfgBookingTypes bookingType;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "rate_code_id", insertable = false, updatable = false)
private CfgRateCodes rateCode;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "source_code_id", insertable = false, updatable = false)
private CfgSourceCodes sourceCode;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "market_code_id", insertable = false, updatable = false)
private CfgMarketCodes marketCode;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "cfg_daylight_mapping_room_types", joinColumns = {@JoinColumn(name = "daylight_id")}, inverseJoinColumns = {@JoinColumn(name = "room_type_id")})
private Set<CfgRoomTypes> daylightRoomType;
//-- For export
@Transient
private String sectionName;
@Transient
private String propertyName;
@Transient
private String bookingTypeName;
@Transient
private String blockName;
@Transient
private String rateCodeName;
@Transient
private String roomTypeNames;
@Transient
private String sourceCodeName;
@Transient
private String marketCodeName;
}
@@ -0,0 +1,33 @@
package com.mgm.mcrm.apigateway.basesetting.mapping.models;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Entity
@Table(name="cfg_market_codes")
@Data
public class CfgMarketCodes implements Serializable {
//fields in table
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="code")
private String code;
@Column(name = "category")
private String category;
@Column(name="created_at")
private LocalDateTime createdAt;
@Column(name="created_by")
private String createdBy;
@Column(name="updated_at")
private LocalDateTime updatedAt;
@Column(name="updated_by")
private String updatedBy;
@Column(name = "dl_market_segment_id")
private String dlMarketSegmentId;
}
@@ -0,0 +1,32 @@
package com.mgm.mcrm.apigateway.basesetting.mapping.models;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Entity
@Table(name = "cfg_rate_codes")
@Data
public class CfgRateCodes implements Serializable {
//fields in table
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "code")
private String code;
@Column(name = "category")
private String category;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Column(name = "updated_by")
private String updatedBy;
@Column(name = "dl_rate_plan_id")
private String dlRatePlanId;
}
@@ -0,0 +1,33 @@
package com.mgm.mcrm.apigateway.basesetting.mapping.models;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Entity
@Table(name = "cfg_source_codes")
@Data
public class CfgSourceCodes implements Serializable {
//fields in table
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "code")
private String code;
@Column(name = "category")
private String category;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Column(name = "updated_by")
private String updatedBy;
@Column(name = "dl_source_id")
private String dlSourceId;
}
@@ -0,0 +1,9 @@
package com.mgm.mcrm.apigateway.basesetting.mapping.repositories;
import com.mgm.mcrm.apigateway.basesetting.mapping.models.CfgBlockCodes;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BlockCodeDao extends JpaRepository<CfgBlockCodes, Long> {
CfgBlockCodes findByDlBlockId(String dlBlockId);
}
@@ -0,0 +1,15 @@
package com.mgm.mcrm.apigateway.basesetting.mapping.repositories;
import com.mgm.mcrm.apigateway.basesetting.mapping.models.CfgBlocks;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface BlockDao extends JpaRepository<CfgBlocks, Long> {
CfgBlocks findById(long id);
@Query(value="select * from cfg_blocks where name =?1",nativeQuery=true)
CfgBlocks getByName(String name);
}
@@ -0,0 +1,68 @@
package com.mgm.mcrm.apigateway.basesetting.mapping.repositories;
import com.mgm.mcrm.apigateway.basesetting.mapping.models.CfgDaylightView;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Optional;
public interface DaylightViewDao extends JpaRepository<CfgDaylightView, Long> {
@EntityGraph(value = "graph.DaylightMapping.fulldetails", type = EntityGraph.EntityGraphType.LOAD)
CfgDaylightView findById(long id);
@EntityGraph(value = "graph.DaylightMapping.fulldetails", type = EntityGraph.EntityGraphType.LOAD)
List<CfgDaylightView> findAll(Specification<CfgDaylightView> spec, Sort sort);
@EntityGraph(value = "graph.DaylightMapping.fulldetails", type = EntityGraph.EntityGraphType.LOAD)
List<CfgDaylightView> findAll(Specification<CfgDaylightView> spec);
Page<CfgDaylightView> findAll(Specification<CfgDaylightView> spec, Pageable pageable);
@EntityGraph(value = "graph.DaylightMapping.fulldetails", type = EntityGraph.EntityGraphType.LOAD)
List<CfgDaylightView> findByPropertyIdAndBookingTypeId(Long propertyId, Long bookingTypeId);
@EntityGraph(value = "graph.DaylightMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD)
List<CfgDaylightView> findByMarketCodeIdAndRateCodeId(Long marketCodeId, Long rateCodeId);
@EntityGraph(value = "graph.DaylightMapping.fulldetails")
@Query("""
SELECT d
FROM CfgDaylightView d
JOIN d.daylightRoomType rt
WHERE d.sectionId = :sectionId
AND d.propertyId = :propertyId
AND d.bookingTypeId = :bookingTypeId
AND rt.id = :roomTypeId
""")
Optional<CfgDaylightView> findBySectionPropertyBookingTypeRoomType(
@Param("sectionId") Long sectionId,
@Param("propertyId") Long propertyId,
@Param("bookingTypeId") Long bookingTypeId,
@Param("roomTypeId") Long roomTypeId
);
@EntityGraph(value = "graph.DaylightMapping.fulldetails")
@Query("""
SELECT d
FROM CfgDaylightView d
JOIN d.daylightRoomType rt
WHERE d.sectionId = :sectionId
AND d.marketCodeId = :marketCodeId
AND d.propertyId = :propertyId
AND rt.id = :roomTypeId
""")
Optional<CfgDaylightView> findBySectionMarketPropertyRoomType(
@Param("sectionId") Long sectionId,
@Param("marketCodeId") Long marketCodeId,
@Param("propertyId") Long propertyId,
@Param("roomTypeId") Long roomTypeId
);
}
@@ -0,0 +1,14 @@
package com.mgm.mcrm.apigateway.basesetting.mapping.repositories;
import com.mgm.mcrm.apigateway.basesetting.mapping.models.CfgMarketCodes;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface MarketCodeDao extends JpaRepository<CfgMarketCodes, String> {
CfgMarketCodes findById(long id);
List<CfgMarketCodes> findByCode(String code);
CfgMarketCodes findByDlMarketSegmentId(String dlMarketSegmentId);
}
@@ -0,0 +1,13 @@
package com.mgm.mcrm.apigateway.basesetting.mapping.repositories;
import com.mgm.mcrm.apigateway.basesetting.mapping.models.CfgRateCodes;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface RateCodeDao extends JpaRepository<CfgRateCodes, String> {
CfgRateCodes findById(long id);
List<CfgRateCodes> findByCode(String code);
CfgRateCodes findByDlRatePlanId(String dlRatePlanId);
}
@@ -0,0 +1,8 @@
package com.mgm.mcrm.apigateway.basesetting.mapping.repositories;
import com.mgm.mcrm.apigateway.basesetting.mapping.models.CfgSourceCodes;
import org.springframework.data.jpa.repository.JpaRepository;
public interface SourceCodeDao extends JpaRepository<CfgSourceCodes, String> {
CfgSourceCodes findById(long id);
}
@@ -0,0 +1,44 @@
package com.mgm.mcrm.apigateway.basesetting.property.models;
import jakarta.persistence.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "cfg_properties")
public class CfgProperties {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "code")
private String code;
@Column(name = "name_zht")
private String nameZht;
@Column(name = "name_zhs")
private String nameZhs;
@Column(name = "category")
private String category;
@Column(name = "hotel_code")
private String hotelCode;
@Column(name = "sort_order")
private Integer sortOrder;
@Column(name = "email_name")
private String emailName;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Column(name = "dl_property_id")
private String dlPropertyId;
@Column(name = "status")
private int status;
}
@@ -0,0 +1,24 @@
package com.mgm.mcrm.apigateway.basesetting.property.repositories;
import com.mgm.mcrm.apigateway.basesetting.property.models.CfgProperties;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
public interface PropertyDao extends JpaRepository<CfgProperties, Long> {
@Query(value="select * from cfg_properties where name=?1",nativeQuery=true)
CfgProperties getByName(String name);
CfgProperties findByDlPropertyId(String dlPropertyId);
List<CfgProperties> findByCategory(String category);
}
@@ -0,0 +1,34 @@
package com.mgm.mcrm.apigateway.basesetting.room.models;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Entity
@Table(name = "cfg_room_types")
@Data
public class CfgRoomTypes implements Serializable {
//fields in table
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "code")
private String code;
@Column(name = "name_cn")
private String nameCN;
@Column(name = "category")
private String category;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Column(name = "updated_by")
private String updatedBy;
@Column(name = "dl_room_type_id")
private String dlRoomTypeId;
}
@@ -0,0 +1,75 @@
package com.mgm.mcrm.apigateway.basesetting.room.models;
import com.mgm.mcrm.apigateway.basesetting.property.models.CfgProperties;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
@Entity
@Table(name = "cfg_rooms")
@NamedEntityGraph(
name = "graph.RoomSetting.fulldetails",
attributeNodes = {
@NamedAttributeNode("roomRoomType"),
@NamedAttributeNode("propertyObj")
}
)
@Data
public class CfgRooms implements Serializable {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "name_cn")
private String nameCN;
@Column(name = "property_id")
private Long propertyId;
@Column(name = "sharer_limit")
private Integer sharerLimit;
@Column(name = "category")
private String category;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Column(name = "updated_by")
private String updatedBy;
@Column(name = "room_category")
private String roomCategory;
@Column(name = "for_booking")
private Integer forCreateBooking;
@Column(name = "for_waitlist")
private Integer forCreateWaitlist;
@Column(name = "email_name")
private String emailName;
@Transient
private List<String> roomTypeIds;
// For export
@Transient
private String propertyName;
@Transient
private String roomTypeNames;
@Transient
private String forCreateBookingValue;
@Transient
private String forCreateWaitlistValue;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "cfg_rooms_room_types", joinColumns = {@JoinColumn(name = "room_id")}, inverseJoinColumns = {@JoinColumn(name = "room_type_id")})
private List<CfgRoomTypes> roomRoomType;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "property_id", insertable = false, updatable = false)
private CfgProperties propertyObj;
}
@@ -0,0 +1,27 @@
package com.mgm.mcrm.apigateway.basesetting.room.models;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name="cfg_rooms_room_types")
@IdClass(CfgRoomsRoomTypesKey.class)
public class CfgRoomsRoomTypes implements Serializable {
//fields in table
@Id
@Column(name="room_id")
private Long roomId;
@Id
@Column(name="room_type_id")
private Long roomTypeId;
@Column(name="created_at")
private LocalDateTime createdAt;
@Column(name="created_by")
private String createdBy;
}
@@ -0,0 +1,46 @@
package com.mgm.mcrm.apigateway.basesetting.room.models;
import java.io.Serializable;
public class CfgRoomsRoomTypesKey implements Serializable{
private Long roomId;
private Long roomTypeId;
public Long getRoomId() {
return roomId;
}
public void setRoomId(Long roomId) {
this.roomId = roomId;
}
public Long getRoomTypeId() {
return roomTypeId;
}
public void setRoomTypeId(Long roomTypeId) {
this.roomTypeId = roomTypeId;
}
@Override
public boolean equals(Object o) {
if(o instanceof CfgRoomsRoomTypesKey)
{
CfgRoomsRoomTypesKey key = (CfgRoomsRoomTypesKey)o ;
if(this.roomId == key.getRoomId() &&
this.roomTypeId == key.getRoomTypeId())
{
return true ;
}
}
return false ;
}
@Override
public int hashCode() {
return 1;
}
}
@@ -0,0 +1,27 @@
package com.mgm.mcrm.apigateway.basesetting.room.repositories;
import com.mgm.mcrm.apigateway.basesetting.room.models.CfgRooms;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface RoomDao extends JpaRepository<CfgRooms, Long> {
@EntityGraph(value = "graph.RoomSetting.fulldetails",type = EntityGraph.EntityGraphType.LOAD)
CfgRooms findById(long id);
@EntityGraph(value = "graph.RoomSetting.fulldetails",type = EntityGraph.EntityGraphType.LOAD)
List<CfgRooms> findAll(Specification<CfgRooms> spec,Sort sort);
@EntityGraph(value = "graph.RoomSetting.fulldetails",type = EntityGraph.EntityGraphType.LOAD)
List<CfgRooms> findAll(Specification<CfgRooms> spec);
Page<CfgRooms> findAll(Specification<CfgRooms> spec, Pageable pageable);
@Query(value="select top(1) id from cfg_rooms where property_id=?1 and " +
" id in (select room_id from cfg_rooms_room_types where room_type_id =?2) ",nativeQuery=true)
Long queryPropertyRoomIdByRoomTypeId(Long propertyId, Long roomTypeId);
}
@@ -0,0 +1,12 @@
package com.mgm.mcrm.apigateway.basesetting.room.repositories;
import com.mgm.mcrm.apigateway.basesetting.room.models.CfgRoomsRoomTypes;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface RoomRoomTypeDao extends JpaRepository<CfgRoomsRoomTypes, String> {
List<CfgRoomsRoomTypes> findByRoomTypeId(Long roomTypeId);
}
@@ -0,0 +1,11 @@
package com.mgm.mcrm.apigateway.basesetting.room.repositories;
import com.mgm.mcrm.apigateway.basesetting.room.models.CfgRoomTypes;
import org.springframework.data.jpa.repository.JpaRepository;
public interface RoomTypeDao extends JpaRepository<CfgRoomTypes, Long> {
CfgRoomTypes findByCodeAndCategory(String code,String category);
CfgRoomTypes findByDlRoomTypeId(String dlRoomTypeId);
}
@@ -0,0 +1,57 @@
package com.mgm.mcrm.apigateway.basesetting.team.models;
import java.io.Serializable;
import java.util.Date;
import com.mgm.mcrm.apigateway.basesetting.property.models.CfgProperties;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.Data;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
@Data
@Entity
@Table(name="app_users")
public class AppUsers implements Serializable {
//fields in table
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="user_id")
private String userId;
@Column(name="team_id")
private Long teamId;
@Column(name="property_id")
private Long propertyId;
@Column(name="authorizer")
private String authorizer;
@Column(name="created_at")
private Date createdAt;
@Column(name="created_by")
private String createdBy;
@Column(name="updated_at")
private Date updatedAt;
@Column(name="updated_by")
private String updatedBy;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="team_id",insertable=false ,updatable=false)
private CfgDepartments userTeam;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="property_id",insertable=false ,updatable=false)
private CfgProperties userProperty;
}
@@ -0,0 +1,34 @@
package com.mgm.mcrm.apigateway.basesetting.team.models;
import java.io.Serializable;
import java.util.Date;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
@Data
@Entity
@Table(name="cfg_departments")
public class CfgDepartments {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="name")
private String name;
@Column(name="created_at")
private Date createdAt;
@Column(name="updated_at")
private Date updatedAt;
@Column(name="created_by")
private String createdBy;
@Column(name="updated_by")
private String updatedBy;
}
@@ -0,0 +1,34 @@
package com.mgm.mcrm.apigateway.basesetting.team.models;
import java.io.Serializable;
import java.util.Date;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
@Data
@Entity
@Table(name="cfg_divisions")
public class CfgDivisions {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="name")
private String name;
@Column(name="created_at")
private Date createdAt;
@Column(name="created_by")
private String createdBy;
@Column(name="updated_at")
private Date updatedAt;
@Column(name="updated_by")
private String updatedBy;
}
@@ -0,0 +1,46 @@
package com.mgm.mcrm.apigateway.basesetting.team.models;
import java.util.Date;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
@Data
@Entity
@Table(name="cfg_other_user_mapping")
public class CfgOtherUserMapping {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="division_id")
private Long divisionId;
@Column(name="department_id")
private Long departmentId;
@Column(name="section_id")
private Long sectionId;
@Column(name="team_id")
private Long teamId;
@Column(name="property_id")
private Long propertyId;
@Column(name="booking_type_id")
private Long bookingTypeId;
@Column(name="market_code_id")
private Long marketCodeId;
@Column(name="segment_id")
private Long segmentId;
@Column(name="created_at")
private Date createdAt;
@Column(name="created_by")
private String createdBy;
@Column(name="updated_at")
private Date updatedAt;
@Column(name="updated_by")
private String updatedBy;
}
@@ -0,0 +1,27 @@
package com.mgm.mcrm.apigateway.basesetting.team.models;
import jakarta.persistence.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "cfg_sections")
public class CfgSections {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_by")
private String updatedBy;
}
@@ -0,0 +1,37 @@
package com.mgm.mcrm.apigateway.basesetting.team.models;
import java.util.Date;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
@Data
@Entity
@Table(name="cfg_team_structure")
public class CfgTeamStructure {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="division_id")
private Long divisionId;
@Column(name="department_id")
private Long departmentId;
@Column(name="section_id")
private Long sectionId;
@Column(name="created_at")
private Date createdAt;
@Column(name="updated_at")
private Date updatedAt;
@Column(name="created_by")
private String createdBy;
@Column(name="updated_by")
private String updatedBy;
}
@@ -0,0 +1,68 @@
package com.mgm.mcrm.apigateway.basesetting.team.models;
import java.util.Date;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.NamedAttributeNode;
import jakarta.persistence.NamedEntityGraph;
import jakarta.persistence.NamedEntityGraphs;
import jakarta.persistence.Table;
import lombok.Data;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
@Data
@Entity
@Table(name="cfg_team_structure")
@NamedEntityGraphs({
@NamedEntityGraph(
name = "graph.TeamStructure.fulldetails",
attributeNodes = {
@NamedAttributeNode("divisionObj"),
@NamedAttributeNode("departmentObj"),
@NamedAttributeNode("sectionObj")
}
)
})
public class CfgTeamStructureView {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="division_id")
private Long divisionId;
@Column(name="department_id")
private Long departmentId;
@Column(name="section_id")
private Long sectionId;
@Column(name="created_at")
private Date createdAt;
@Column(name="updated_at")
private Date updatedAt;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="division_id",insertable=false ,updatable=false)
private CfgDivisions divisionObj;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="department_id",insertable=false ,updatable=false)
private CfgDepartments departmentObj;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="section_id",insertable=false ,updatable=false)
private CfgSections sectionObj;
}
@@ -0,0 +1,9 @@
package com.mgm.mcrm.apigateway.basesetting.team.repositories;
import com.mgm.mcrm.apigateway.basesetting.team.models.AppUsers;
import org.springframework.data.jpa.repository.JpaRepository;
public interface AppUserDao extends JpaRepository<AppUsers, Long> {
AppUsers findById(long id);
}
@@ -0,0 +1,13 @@
package com.mgm.mcrm.apigateway.basesetting.team.repositories;
import com.mgm.mcrm.apigateway.basesetting.team.models.CfgDepartments;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface DepartmentDao extends JpaRepository<CfgDepartments, Long> {
@Query(value = "select * from cfg_departments with (nolock) where name=?1", nativeQuery = true)
CfgDepartments getByName(String name);
}
@@ -0,0 +1,16 @@
package com.mgm.mcrm.apigateway.basesetting.team.repositories;
import com.mgm.mcrm.apigateway.basesetting.team.models.CfgDivisions;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface DivisionDao extends JpaRepository<CfgDivisions, Long> {
CfgDivisions findById(long id);
@Query(value="select * from cfg_divisions where name =?1",nativeQuery=true)
CfgDivisions getByName(String name);
}
@@ -0,0 +1,14 @@
package com.mgm.mcrm.apigateway.basesetting.team.repositories;
import com.mgm.mcrm.apigateway.basesetting.team.models.CfgSections;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface SectionDao extends JpaRepository<CfgSections, Long> {
@Query(value = "select * from cfg_sections with (nolock) where name=?1", nativeQuery = true)
CfgSections getByName(String name);
}
@@ -0,0 +1,14 @@
package com.mgm.mcrm.apigateway.basesetting.team.repositories;
import com.mgm.mcrm.apigateway.basesetting.team.models.CfgTeamStructure;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface TeamStructureDao extends JpaRepository<CfgTeamStructure, Long> {
@Query(value = "select * from cfg_team_structure with (nolock) where division_id=?1 and department_id=?2 and section_id=?3", nativeQuery = true)
CfgTeamStructure getByDivisionIdAndDepartmentIdAndSectionId(Long divisionId,Long departmentId,Long sectionId);
}
@@ -0,0 +1,21 @@
package com.mgm.mcrm.apigateway.basesetting.team.repositories;
import java.util.List;
import com.mgm.mcrm.apigateway.basesetting.team.models.CfgTeamStructureView;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
public interface TeamStructureViewDao extends JpaRepository<CfgTeamStructureView, Long> {
@EntityGraph(value = "graph.TeamStructure.fulldetails",type = EntityGraph.EntityGraphType.LOAD)
List<CfgTeamStructureView> findAll(Specification<CfgTeamStructureView> spec);
@EntityGraph(value = "graph.TeamStructure.fulldetails",type = EntityGraph.EntityGraphType.LOAD)
List<CfgTeamStructureView> findAll(Specification<CfgTeamStructureView> spec, Sort sort);
}
@@ -0,0 +1,30 @@
package com.mgm.mcrm.apigateway.common.config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
@Bean(name = "mgmDataSource")
@Qualifier("mgmDataSource")
@ConfigurationProperties(prefix = "spring.datasource.mgm")
@Primary
public DataSource mgmDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "operaDataSource")
@Qualifier("operaDataSource")
@ConfigurationProperties(prefix = "spring.datasource.opera")
public DataSource operaDataSource() {
return DataSourceBuilder.create().build();
}
}
@@ -0,0 +1,89 @@
package com.mgm.mcrm.apigateway.common.config;
import com.mgm.mcrm.apigateway.common.constants.SysCommon;
import com.mgm.mcrm.apigateway.common.dtos.config.DaylightApiSetting;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DaylightProxyConfig {
@Value("${mcrm.proxy.api-config.daylight.server-url}")
private String serverUrl;
@Value("${mcrm.proxy.api-config.daylight.request-timeout:60}")
private int requestTimeout;
@Value("${mcrm.proxy.api-config.daylight.token.token-url}")
private String tokenUrl;
@Value("${mcrm.proxy.api-config.daylight.token.username}")
private String userName;
@Value("${mcrm.proxy.api-config.daylight.token.password}")
private String password;
@Value("${mcrm.proxy.api-config.daylight.token.grant-type}")
private String grantType;
@Value("${mcrm.proxy.api-config.daylight.token.client-id}")
private String clientId;
@Value("${mcrm.proxy.api-config.daylight.token.client-secret}")
private String clientSecret;
@Value("${mcrm.proxy.api-config.daylight.token.request-timeout:60}")
private int tokenRequestTimeout;
@Value("${mcrm.proxy.api-config.daylight.token.default-expiry-second:800}")
private long tokenExpirySecond;
@Value("${mcrm.proxy.api-config.daylight.security.authorization-data}")
private String appAuthorizationData;
//-- Proxy setting for daylight
@Value("${mcrm.proxy.api-config.daylight.proxy-setting.host}")
private String proxyHost;
@Value("${mcrm.proxy.api-config.daylight.proxy-setting.port:443}")
private String proxyPort;
@Value("${mcrm.proxy.api-config.daylight.proxy-setting.auth.username}")
private String proxyUsername;
@Value("${mcrm.proxy.api-config.daylight.proxy-setting.auth.password}")
private String proxyPassword;
//-- SSL config for daylight
@Value("${mcrm.proxy.api-config.daylight.ssl-bundle-name}")
private String sslBundleName;
@Bean
public DaylightApiSetting configDaylightApi() {
DaylightApiSetting config = new DaylightApiSetting();
config.setServerUrl(serverUrl);
config.setApiTimeout(requestTimeout);
config.setTokenUrl(tokenUrl);
config.setUsername(userName);
config.setPassword(password);
config.setGrantType(grantType);
config.setClientId(clientId);
config.setClientSecret(clientSecret);
config.setTokenRequestTimeout(tokenRequestTimeout);
config.setTokenExpireSecond(tokenExpirySecond);
//--
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.registerAuthorizationList(SysCommon.extractAuthorizationItems(appAuthorizationData));
return config;
}
}
@@ -0,0 +1,52 @@
package com.mgm.mcrm.apigateway.common.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.EmailProxySetting;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class EmailProxyConfig {
@Value("${mcrm.proxy.api-config.notification.email-sender.smtp-server}")
private String smtpServer;
@Value("${mcrm.proxy.api-config.notification.email-sender.smtp-port}")
private int smtpPort;
@Value("${mcrm.proxy.api-config.notification.email-sender.username}")
private String userName;
@Value("${mcrm.proxy.api-config.notification.email-sender.password}")
private String password;
@Value("${mcrm.proxy.api-config.notification.email-sender.smtp-auth}")
private boolean smtpAuth;
@Value("${mcrm.proxy.api-config.notification.email-sender.starttls}")
private boolean startTls;
@Value("${mcrm.proxy.api-config.notification.email-sender.default-send-to}")
private String defaultSentTo;
@Value("${mcrm.proxy.api-config.notification.security.authorization-data}")
private String appAuthorizationData;
@Bean
public EmailProxySetting configEmailProxy() {
EmailProxySetting config = new EmailProxySetting();
config.setSmtpServer(smtpServer);
config.setSmtpPort(smtpPort);
config.setUsername(userName);
config.setPassword(password);
config.setAuth(smtpAuth);
config.setStarttls(startTls);
config.setDefaultSendTo(defaultSentTo);
config.registerAuthorizationList(SysCommon.extractAuthorizationItems(appAuthorizationData));
return config;
}
}
@@ -0,0 +1,77 @@
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 org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class EsbProxyConfig {
@Value("${mcrm.proxy.api-config.esb.server-url}")
private String serverUrl;
@Value("${mcrm.proxy.api-config.esb.request-timeout:60}")
private int apiRequestTimeout;
@Value("${mcrm.proxy.api-config.esb.token.token-url}")
private String tokenUrl;
@Value("${mcrm.proxy.api-config.esb.token.app-id}")
private String appId;
@Value("${mcrm.proxy.api-config.esb.token.app-secret}")
private String appSecret;
@Value("${mcrm.proxy.api-config.esb.token.request-timeout:60}")
private int tokenRequestTimeout;
@Value("${mcrm.proxy.api-config.esb.token.default-expiry-second:800}")
private long tokenExpirySecond;
@Value("${mcrm.proxy.api-config.esb.security.authorization-data}")
private String appAuthorizationData;
//-- Proxy setting for esb
@Value("${mcrm.proxy.api-config.esb.proxy-setting.host}")
private String proxyHost;
@Value("${mcrm.proxy.api-config.esb.proxy-setting.port:443}")
private String proxyPort;
@Value("${mcrm.proxy.api-config.esb.proxy-setting.auth.username}")
private String proxyUsername;
@Value("${mcrm.proxy.api-config.esb.proxy-setting.auth.password}")
private String proxyPassword;
//-- SSL config for esb
@Value("${mcrm.proxy.api-config.esb.ssl-bundle-name}")
private String sslBundleName;
@Bean
public EsbApiSetting configEsbApi() {
EsbApiSetting config = new EsbApiSetting();
config.setServerUrl(serverUrl);
config.setApiRequestTimeout(apiRequestTimeout);
config.setTokenUrl(tokenUrl);
config.setAppId(appId);
config.setAppSecret(appSecret);
config.setTokenRequestTimeout(tokenRequestTimeout);
config.setTokenExpireSecond(tokenExpirySecond);
//--
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.registerAuthorizationList(SysCommon.extractAuthorizationItems(appAuthorizationData));
return config;
}
}
@@ -0,0 +1,26 @@
package com.mgm.mcrm.apigateway.common.config;
import lombok.Data;
/**
* HTTP 請求頭配置類
* 用於自定義 HTTP 請求頭的值
*
* @author System
*/
@Data
public class HttpHeader {
public static final String ACCEPT = "Accept";
public static final String ACCEPT_CHARSET = "Accept-Charset";
public static final String ACCEPT_ENCODING = "Accept-Encoding";
public static final String ACCEPT_LANGUAGE = "Accept-Language";
public static final String ACCEPT_RANGES = "Accept-Ranges";
public static final String AUTHORIZATION = "Authorization";
public static final String CACHE_CONTROL = "Cache-Control";
public static final String CONNECTION = "Connection";
public static final String COOKIE = "Cookie";
public static final String CONTENT_LENGTH = "Content-Length";
public static final String CONTENT_TYPE = "Content-Type";
public static final String USER_AGENT = "user-agent";
}
@@ -0,0 +1,72 @@
package com.mgm.mcrm.apigateway.common.config;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
/**
* @Description: 主数据源配置
* @date
*/
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager",
basePackages = {"com.mgm.mcrm.apigateway"})
public class MGMDataSourceConfig {
@Autowired
@Qualifier("mgmDataSource")
private DataSource mrbsDataSource;
@Primary
@Bean(name = "mgmJpaProperties")
@ConfigurationProperties(prefix = "spring.jpa.mgm")
public JpaProperties jpaProperties() {
return new JpaProperties();
}
@Primary
@Bean(name = "entityManager")
public EntityManager entityManager( @Qualifier("entityManagerFactory") EntityManagerFactory factory) {
return factory.createEntityManager();
}
@Primary
@Bean(name = "entityManagerFactory") //mrbs实体工厂
public LocalContainerEntityManagerFactoryBean entityManagerFactory (@Qualifier("mgmDataSource") DataSource mgmDataSource,
@Qualifier("mgmJpaProperties") JpaProperties jpaProperties,EntityManagerFactoryBuilder builder) {
return builder.dataSource(mgmDataSource)
.properties(jpaProperties.getProperties())
.properties(
new HibernateProperties()
.determineHibernateProperties(
jpaProperties.getProperties(), new HibernateSettings()))
.packages("com.mgm.mcrm.apigateway") //实体类所在位置
.persistenceUnit("mgmPersistenceUnit")
.build();
}
@Primary
@Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(@Qualifier("entityManagerFactory") EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}
}
@@ -0,0 +1,66 @@
package com.mgm.mcrm.apigateway.common.config;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
/**
* @Description: 副数据源配置
* @date
*/
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactoryOpera",
transactionManagerRef = "transactionManagerOpera")
public class OperaDataSourceConfig {
@Autowired
@Qualifier("operaDataSource")
private DataSource operaDataSource;
@Bean(name = "operaJpaProperties")
@ConfigurationProperties(prefix = "spring.jpa.opera")
public JpaProperties jpaProperties() {
return new JpaProperties();
}
@Bean(name = "entityManagerOpera")
public EntityManager entityManager( @Qualifier("entityManagerFactoryOpera") EntityManagerFactory factory) {
return factory.createEntityManager();
}
@Bean(name = "entityManagerFactoryOpera")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryOpera (@Qualifier("operaDataSource") DataSource operaDataSource,
@Qualifier("operaJpaProperties") JpaProperties jpaProperties,EntityManagerFactoryBuilder builder) {
return builder.dataSource(operaDataSource)
.properties(jpaProperties.getProperties())
.properties(
new HibernateProperties()
.determineHibernateProperties(
jpaProperties.getProperties(), new HibernateSettings()))
.packages("com.mgm.daylight.booking.models") //实体类所在位置
.persistenceUnit("operaPersistenceUnit")
.build();
}
@Bean(name = "transactionManagerOpera")
public PlatformTransactionManager transactionManagerOpera(@Qualifier("entityManagerFactoryOpera") EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}
}
@@ -0,0 +1,57 @@
package com.mgm.mcrm.apigateway.common.config;
import com.mgm.mcrm.apigateway.common.constants.SysCommon;
import com.mgm.mcrm.apigateway.common.dtos.config.OperaApiSetting;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class OperaProxyConfig {
@Value("${mcrm.proxy.api-config.opera.server-url}")
private String serverUrl;
@Value("${mcrm.proxy.api-config.opera.request-timeout:10000}")
private int requestTimeout;
@Value("${mcrm.proxy.api-config.opera.security.authorization-data}")
private String appAuthorizationData;
//-- Proxy setting for opera
@Value("${mcrm.proxy.api-config.opera.proxy-setting.host}")
private String proxyHost;
@Value("${mcrm.proxy.api-config.opera.proxy-setting.port:443}")
private String proxyPort;
@Value("${mcrm.proxy.api-config.opera.proxy-setting.auth.username}")
private String proxyUsername;
@Value("${mcrm.proxy.api-config.opera.proxy-setting.auth.password}")
private String proxyPassword;
//-- SSL config for opera
@Value("${mcrm.proxy.api-config.opera.ssl-bundle-name}")
private String sslBundleName;
@Bean
public OperaApiSetting configOperaApi() {
OperaApiSetting config = new OperaApiSetting();
config.setServerUrl(serverUrl);
config.setTimeout(requestTimeout);
//--
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.registerAuthorizationList(SysCommon.extractAuthorizationItems(appAuthorizationData));
return config;
}
}
@@ -0,0 +1,18 @@
package com.mgm.mcrm.apigateway.common.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("API Document for MGM MCRM API Gateway Application")
.version("1.0")
.description("API Document for MGM MCRM API Gateway Application"));
}
}
@@ -0,0 +1,32 @@
package com.mgm.mcrm.apigateway.common.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import com.mgm.mcrm.apigateway.logging.filters.WebhookLoggingFilter;
@Configuration
public class WebFilterConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduling = new ThreadPoolTaskScheduler();
scheduling.setPoolSize(20);
scheduling.initialize();
return scheduling;
}
@Bean
public FilterRegistrationBean<WebhookLoggingFilter> registerWebhookFilter(
WebhookLoggingFilter webhookLoggingFilter) {
FilterRegistrationBean<WebhookLoggingFilter> registration = new FilterRegistrationBean<WebhookLoggingFilter>();
registration.setFilter(webhookLoggingFilter);
registration.addUrlPatterns("/api/daylight/webhook/*");
registration.setOrder(3);
registration.setName("webhookLoggingFilter");
return registration;
}
}
@@ -0,0 +1,173 @@
package com.mgm.mcrm.apigateway.common.constants;
import java.util.Locale;
/**
* 通用常量信息
*
* @author Aaka
*/
public class Constants
{
/**
* UTF-8 字符集
*/
public static final String UTF8 = "UTF-8";
/**
* GBK 字符集
*/
public static final String GBK = "GBK";
/**
* 系统语言
*/
public static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;
/**
* www主域
*/
public static final String WWW = "www.";
/**
* http请求
*/
public static final String HTTP = "http://";
/**
* https请求
*/
public static final String HTTPS = "https://";
/**
* 通用成功标识
*/
public static final String SUCCESS = "0";
/**
* 通用失败标识
*/
public static final String FAIL = "1";
/**
* 登录成功
*/
public static final String LOGIN_SUCCESS = "Success";
/**
* 注销
*/
public static final String LOGOUT = "Logout";
/**
* 注册
*/
public static final String REGISTER = "Register";
/**
* 登录失败
*/
public static final String LOGIN_FAIL = "Error";
/**
* 所有权限标识
*/
public static final String ALL_PERMISSION = "*:*:*";
/**
* 管理员角色权限标识
*/
public static final String SUPER_ADMIN = "admin";
/**
* 角色权限分隔符
*/
public static final String ROLE_DELIMETER = ",";
/**
* 权限标识分隔符
*/
public static final String PERMISSION_DELIMETER = ",";
/**
* 验证码有效期(分钟)
*/
public static final Integer CAPTCHA_EXPIRATION = 2;
/**
* 令牌
*/
public static final String TOKEN = "token";
/**
* 令牌前缀
*/
public static final String TOKEN_PREFIX = "Bearer ";
/**
* 令牌前缀
*/
public static final String LOGIN_USER_KEY = "login_user_key";
/**
* 用户ID
*/
public static final String JWT_USERID = "userid";
/**
* 用户名称
*/
// public static final String JWT_USERNAME = Claims.SUBJECT;
/**
* 用户头像
*/
public static final String JWT_AVATAR = "avatar";
/**
* 创建时间
*/
public static final String JWT_CREATED = "created";
/**
* 用户权限
*/
public static final String JWT_AUTHORITIES = "authorities";
/**
* 资源映射路径 前缀
*/
public static final String RESOURCE_PREFIX = "/profile";
/**
* RMI 远程方法调用
*/
public static final String LOOKUP_RMI = "rmi:";
/**
* LDAP 远程方法调用
*/
public static final String LOOKUP_LDAP = "ldap:";
/**
* LDAPS 远程方法调用
*/
public static final String LOOKUP_LDAPS = "ldaps:";
/**
* 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全)
*/
public static final String[] JSON_WHITELIST_STR = { "com.ruoyi" };
/**
* 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
*/
public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.quartz.task" };
/**
* 定时任务违规的字符
*/
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
"org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config", "com.ruoyi.generator" };
}
@@ -0,0 +1,60 @@
package com.mgm.mcrm.apigateway.common.constants;
public class SettingConstants {
public static final String ENABLE_CUSTOM_DATE = "ENABLE_CUSTOM_DATE";
public static final String CUSTOM_CUR_DATE = "CUSTOM_CUR_DATE";
public static final String ENABLE_EXT_IP_CHECK = "ENABLE_EXT_IP_CHECK";
public static final String ENABLE_EXTERNAL_SEARCH_RESTRICTION = "ENABLE_EXTERNAL_SEARCH_RESTRICTION";
public static final String ENABLE_DEFAULT_ROOM_PRICE = "ENABLE_DEFAULT_ROOM_PRICE";
public static final String ENABLE_ROOM_EXTENSION = "ENABLE_ROOM_EXTENSION";
public static final String BOOKING_MAX_NIGHTS = "BOOKING_MAX_NIGHTS";
public static final String BOOKING_MAX_ROOMS = "BOOKING_MAX_ROOMS";
public static final String BOOKING_MAX_FUTURE_DATE = "BOOKING_MAX_FUTURE_DATE";
public static final String BOOKING_MAX_OCCUPANCY_PER_ROOM = "BOOKING_MAX_OCCUPANCY_PER_ROOM";
public static final String CANCEL_CUTOFF_TIME = "CANCEL_CUTOFF_TIME";
public static final String ENABLE_AUTO_DEPLOY = "ENABLE_AUTO_DEPLOY";
public static final String ENABLE_OWS_TRACE = "ENABLE_OWS_TRACE";
public static final String ENABLE_UUID_CHECK = "ENABLE_UUID_CHECK";
public static final String ENABLE_ADMINER = "ENABLE_ADMINER";
public static final String SESSION_MAX_IDLE_MINUTES = "SESSION_MAX_IDLE_MINUTES";
public static final String GCM_COMMENT_TYPE = "GCM_COMMENT_TYPE";
public static final String ENABLE_TRACE_LOG = "ENABLE_TRACE_LOG";
//phase 2
public static final String ENABLE_APPROVAL = "ENABLE_APPROVAL";
public static final String APPROVAL_EXPIRE_MINUTES = "APPROVAL_EXPIRE_MINUTES";
//ows fix
public static final String OWS_FETCH_MAX_BOOKINGS = "OWS_FETCH_MAX_BOOKINGS";
public static final String[] EXTENDABLE_STATUSES = {"CHECKED_IN","DUE_OUT"};
//ApprovalConstants
public static final String APPROVAL_PERIOD = "APPROVAL_PERIOD";
public static final String GCOMP_BALANCE = "GCOMP_BALANCE";
public static final String DCOMP_BALANCE = "DCOMP_BALANCE";
public static final String ROOM_EXTENSION = "ROOM_EXTENSION";
public static final String ADD_SHARE = "ADD_SHARE";
//ApprovalPeriod
public static final Integer APPROVAL_PERIOD_TYPE_NEW_BOOKING = 1;
public static final Integer APPROVAL_PERIOD_TYPE_EXTENSION = 2;
public static final Integer MEMBER_ID_LENGTH = 8;
//RoomRCDRate
public static final Integer BOOKING_TYPE_NEW = 1;
public static final Integer BOOKING_TYPE_EXTENSION = 2;
//NotificationHelper
public static final Integer EMAIL_TYPE_NEW_BOOKING = 1;
public static final Integer EMAIL_TYPE_MODIFY = 2;
public static final Integer EMAIL_TYPE_EXTEND = 3;
public static final Integer EMAIL_TYPE_CANCEL = 4;
}
@@ -0,0 +1,102 @@
package com.mgm.mcrm.apigateway.common.constants;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
import com.mgm.mcrm.apigateway.common.utils.LogUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class SysCommon {
public static String runtime_path = "";
public static String runtimeName="crm_gateway_runtime";
public static boolean isMock = true;
public static String getSystemPath() {
ApplicationHome h = new ApplicationHome(SysCommon.class);
File f = h.getSource();
return f.getParentFile().toString();
}
public static void initRuntimePath() {
runtime_path = getSystemPath();
}
//-- Path Type 1= Class path 2=Application path 3=URI Path
public static String loadResFileContentByPath(String filePath, int pathType) {
String fileContent = "";
InputStream ifs = null;
BufferedReader bufferedReader = null;
InputStreamReader fileReader = null;
try {
if(pathType==2) {
String applicationPath = SysCommon.runtime_path+"/"+runtimeName;
File dataFile = new File(applicationPath+filePath);
ifs=new FileInputStream(dataFile);
}else {
Resource resource = new ClassPathResource(filePath);
ifs = resource.getInputStream();
}
fileReader = new InputStreamReader(ifs, "UTF-8");
bufferedReader = new BufferedReader(fileReader);
String lineData = null;
int lineCnt =0;
StringBuffer contentBuffer = new StringBuffer();
while ((lineData = bufferedReader.readLine()) != null) {
if(lineCnt>0) {
contentBuffer.append("\n");
}
contentBuffer.append(lineData);
lineCnt++;
}
bufferedReader.close();
fileContent = contentBuffer.toString();
} catch (Exception e) {
//e.printStackTrace();
LogUtil.error(SysCommon.class, "Get Data File failed:"+e.getMessage());
} finally {
try {
if (bufferedReader != null) {
bufferedReader.close();
}
if(fileReader!=null) {
fileReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//--
return fileContent;
}
public static Map<String,String> extractAuthorizationItems(String appAuthorizationData){
Map<String,String> result = new HashMap<>();
if(StringUtils.isNotBlank(appAuthorizationData)){
String[] securityItems = appAuthorizationData.split("[;,]");
for(String securityItem:securityItems){
String[] itemTags = securityItem.split("/");
if(itemTags.length>=2){
String appId = itemTags[0].replace("[","").replace("]","").trim().toUpperCase();
String securityKey = itemTags[1].replace("[","").replace("]","").trim();
if(StringUtils.isNotBlank(appId) && StringUtils.isNotBlank(securityKey)){
result.put(appId,securityKey);
}
}
}
}
return result;
}
}
@@ -0,0 +1,48 @@
package com.mgm.mcrm.apigateway.common.constants;
public class SysConstants {
public static final String CURRENT_USER_KEY = "currentUser";
public static final String SUPER_ADMIN_ID ="1";
public static final int ACTIVE = 1;
public static final int INACTIVE = 0;
public static final int STATUS_OK =200;
public static final int STATUS_AUTH_X_FAILED =401;
public static final int STATUS_PARAMETER_ERROR =422;
public static final int STATUS_GAME_NOT_AVAILABLE =301;
public static final int STATUS_NO_GAME_CHANCE =302;
public static final int STATUS_NO_RESULT =303;
public static final int STATUS_DUPLICATED =304;
public static final int STATUS_REQUEST_INVALID =305;
public static final int STATUS_REQUEST_TIMEOUT =306;
public static final int STATUS_INVALID_REWARD_SETTING =307;
public static final int STATUS_GAME_SESSION_TIMEOUT =308;
public static final int STATUS_NO_CUST_TIER =309;
public static final int STATUS_NO_REWARD =310;
public static final int STATUS_REQUEST_ERROR =701;
public static final String TIER_RED="Red";
public static final String TIER_GOLD="Gold";
public static final String TIER_DIAMOND="Diamond";
public static final String TIER_CHAIRMAN="Chairman";
// cfg_settings
public static final String MAX_BOOKING_STAY_DAYS="MAX_BOOKING_STAY_DAYS";
public static final String MAX_ADVANCE_BOOKING_DAYS="MAX_ADVANCE_BOOKING_DAYS";
public static final String NUM_OF_MULTIPLE_DATE_RANGE="NUM_OF_MULTIPLE_DATE_RANGE";
public static final String PROTECTION_PERIOD_CHECKIN="PROTECTION_PERIOD_CHECKIN";
public static final String PROTECTION_PERIOD_CHECKOUT="PROTECTION_PERIOD_CHECKOUT";
public static final String PROTECT_PERIOD_ENABLE="PROTECT_PERIOD_ENABLE";
public static final String MAX_PREVIOUS_BOOKING_DAYS="MAX_PREVIOUS_BOOKING_DAYS";
// Token
public static final int CMS_TOKEN_TYPE=0;
public static final int MOBILE_TOKEN_TYPE=1;
public static final String PERMISSION_APP_VIEW_BOOKING="10001_01";
public static final String PERMISSION_APP_NEW_BOOKING="10001_02";
public static final String PERMISSION_APP_TODO_LIST="10001_03";
public static final String PERMISSION_APP_DASHBOARD="10001_04";
}
@@ -0,0 +1,12 @@
package com.mgm.mcrm.apigateway.common.dtos;
import lombok.Data;
@Data
public class BaseApiResponse {
private boolean success = false;
private String code;
private String message;
private String content;
private int statusCode=-1;
}
@@ -0,0 +1,21 @@
package com.mgm.mcrm.apigateway.common.dtos;
import com.mgm.mcrm.apigateway.daylight.common.dtos.TokenResponse;
import lombok.Getter;
public class CachedToken {
@Getter
private final TokenResponse token;
private final long expireTime;
public CachedToken(TokenResponse token, long expireTime) {
this.token = token;
this.expireTime = expireTime;
}
public boolean isExpired() {
return System.currentTimeMillis() > expireTime;
}
}
@@ -0,0 +1,69 @@
package com.mgm.mcrm.apigateway.common.dtos;
import lombok.Data;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.ProtocolVersion;
import org.apache.hc.core5.http.message.StatusLine;
@Data
public class HttpReqResp {
/**
* 执行结果-body
*/
private String result;
/**
* 状态码-statusCode
*/
private int statusCode;
/**
* 状态行-StatusLine
*/
private StatusLine statusLine;
/**
* 请求头信息
*/
private Header[] reqHeaders;
/**
* 响应头信息
*/
private Header[] respHeaders;
/**
* 协议版本
*/
private ProtocolVersion protocolVersion;
/**
* HttpResponse结果对象
*/
private HttpResponse resp;
public HttpReqResp(HttpResponse resp) {
// HttpClient 5 API: 使用 new StatusLine(response) 创建 StatusLine
this.statusLine = new StatusLine(resp);
// HttpClient 5 API: 使用 getHeaders() 获取所有响应头
this.respHeaders = resp.getHeaders();
// HttpClient 5 API: 从 StatusLine 获取协议版本
this.protocolVersion = this.statusLine.getProtocolVersion();
// HttpClient 5 API: 使用 getCode() 获取状态码
this.statusCode = resp.getCode();
this.resp = resp;
}
/**
* 从返回的头信息中查询指定头信息
*
* @param name 头信息名称
*/
public Header getHeaders(final String name) {
Header[] headers = this.resp.getHeaders(name);
return headers!=null && headers.length>0?headers[0]:null;
}
}
@@ -0,0 +1,15 @@
package com.mgm.mcrm.apigateway.common.dtos;
import lombok.Data;
import org.springframework.http.HttpHeaders;
@Data
public class HttpResult {
private String result;
private int statusCode;
private HttpHeaders responseHeaders;
private String responseBody;
private String errorMessage;
private String exceptionClass;
}
@@ -0,0 +1,11 @@
package com.mgm.mcrm.apigateway.common.dtos;
import lombok.Data;
@Data
public class ResFileResult {
private boolean success = false;
private String fileName;
private String filePath;
private String errorMessage;
}
@@ -0,0 +1,12 @@
package com.mgm.mcrm.apigateway.common.dtos;
import lombok.Data;
@Data
public class ServiceResult {
private String errorCode;
private boolean isSuccess=false;
private String errorMessage="";
private Object returnData =null;
private Object oldData=null;
}
@@ -0,0 +1,47 @@
package com.mgm.mcrm.apigateway.common.dtos.config;
import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Value;
import java.util.HashMap;
import java.util.Map;
@Data
public class DaylightApiSetting {
//-- Daylight Server
private String serverUrl="";
private int apiTimeout=0;
private String tokenUrl="";
private String username;
private String password;
private String grantType;
private String clientId;
private String clientSecret;
//--Proxy config
private String proxyHost;
private int proxyPort;
private String proxyUserName;
private String proxyPassword;
//--SSL config
private String sslBundleName;
private int tokenRequestTimeout;
private long tokenExpireSecond;
@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);
}
}
@@ -0,0 +1,34 @@
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 EmailProxySetting {
private int smtpPort=25;
private String smtpServer= "";
private String username= "";
private String password= "";
private boolean auth=false;
private boolean starttls=false;
private String defaultSendTo="";
@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);
}
}
@@ -0,0 +1,42 @@
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 EsbApiSetting {
//-- ESB Server
private String serverUrl="";
private int apiRequestTimeout;
private String tokenUrl="";
private String appId="";
private String appSecret="";
//--Proxy config
private String proxyHost;
private int proxyPort;
private String proxyUserName;
private String proxyPassword;
//--SSL config
private String sslBundleName;
private int tokenRequestTimeout;
private long tokenExpireSecond;
@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);
}
}
@@ -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 OperaApiSetting {
//-- OWS Server
private String serverUrl= "";
private int timeout=0;
//--Proxy config
private String proxyHost;
private int proxyPort;
private String proxyUserName;
private String proxyPassword;
//--SSL config
private String sslBundleName;
@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);
}
}
@@ -0,0 +1,17 @@
package com.mgm.mcrm.apigateway.common.dtos.webhook;
import lombok.Data;
import java.time.Instant;
@Data
public class BatchWebhookEventEntry {
private Instant timestamp;
private String messageId;
private String propertyId;
private String topic;
private String eventType;
private String correlationId;
private String payload;
private long batchSequence;
}
@@ -0,0 +1,11 @@
package com.mgm.mcrm.apigateway.common.dtos.webhook;
import lombok.Data;
import java.util.List;
@Data
public class ShijiBatchWebhookEvent {
private List<BatchWebhookEventEntry> results;
private int count;
}
@@ -0,0 +1,56 @@
package com.mgm.mcrm.apigateway.common.enums;
public enum DeliveryReceiptState {
ESME_ROK(0, "Ok - Message Acceptable"),
ESME_RINVMSGLEN(1, "Invalid Message Length"),
ESME_RINVCMDLEN(2, "Invalid Command Length"),
ESME_RINVCMDID(3, "Invalid Command ID"),
ESME_RINVBNDSTS(4, "Invalid bind status"),
ESME_RALYBND(5, "Bind attempted when already bound"),
ESME_RINVPRTFLG(6, "Invalid priority flag"),
ESME_RINVREGDLVFLG(7, "Invalid registered-delivery flag"),
ESME_RSYSERR(8, "SMSC system error"),
ESME_RINVSRCADR(9, "Invalid source address"),
ESME_RINVDSTADR(11, "Invalid destination address"),
ESME_RINVMSGID(12, "Invalid message-id"),
NOT_FOUND(000, "Couldn't resolve.Ask admin to add.");
private int value;
private String description;
DeliveryReceiptState(int value, String description) {
this.value = value;
this.description = description;
}
public static DeliveryReceiptState getDescription(int value) {
for (DeliveryReceiptState item : values()) {
if (item.value() == value) {
return item;
}
}
return NOT_FOUND;
}
public int value() {
return value;
}
public String description() {
return description;
}
}
@@ -0,0 +1,87 @@
package com.mgm.mcrm.apigateway.common.enums;
public enum EumnDaylightStatus {
DUE_IN("DUE IN","DUE_IN"),
DUE_IN_UNDERSCORE("DUE_IN","DUE_IN"),
DUEIN("DUEIN","DUE_IN"),
RESERVED("RESERVED","RESERVED"),
RESERVE("Reserved","RESERVED"),
CHECKEDIN("Checked in","CHECKED_IN"),
CHECKED_IN("CHECKED IN","CHECKED_IN"),
CHECKED_IN_UNDERSCORE("CHECKED_IN","CHECKED_IN"),
CHECK_IN("CHECK_IN","CHECKED_IN"),
CHECK_IN_IN_HOUSE("CHECK_IN(IN_HOUSE)","CHECKED_IN"),
CHECKED_OUT("CHECKED OUT","CHECKED_OUT"),
CHECKED_OUT_UNDERSCORE("CHECKED_OUT","CHECKED_OUT"),
INHOUSE("INHOUSE","CHECKED_IN"),
IN_HOUSE("IN-HOUSE","CHECKED_IN"),
IN_HOUSE_UNDERSCORE("IN_HOUSE","CHECKED_IN"),
IN("IN","CHECKED_IN"),
IH("IH","CHECKED_IN"),
DUE_OUT("DUE OUT","DUE_OUT"),
DUE_OUT_UNDERSCORE("DUE_OUT","DUE_OUT"),
DUEOUT("DUEOUT","DUE_OUT"),
CANCELED("CANCELED","CANCELED"),
CANCELLED("CANCELLED","CANCELED"),
NO_SHOW("NO SHOW","CANCELED"),
NOSHOW("NOSHOW","CANCELED");
private String key;
private String value;
EumnDaylightStatus(String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
public static String getStatusByDaylightStatus(String key) {
if (key == null) {
return "UNKNOWN";
}
String normalizedKey = key.trim();
EumnDaylightStatus[] objs = values();
for (EumnDaylightStatus obj : objs) {
if (obj.getKey().equalsIgnoreCase(normalizedKey)) {
return obj.getValue();
}
}
String compactKey = normalizeStatusKey(normalizedKey);
for (EumnDaylightStatus obj : objs) {
String compactObjKey = normalizeStatusKey(obj.getKey());
if (compactObjKey.equalsIgnoreCase(compactKey)) {
return obj.getValue();
}
}
if (compactKey.contains("CHECKIN") || compactKey.contains("INHOUSE")) {
return "CHECKED_IN";
}
if (compactKey.contains("CANCEL")) {
return "CANCELED";
}
return "UNKNOWN";
}
private static String normalizeStatusKey(String key) {
return key == null ? "" : key.replaceAll("[^A-Za-z0-9]", "");
}
public static boolean isInclude(String value){
boolean include = false;
for (EumnDaylightStatus e: EumnDaylightStatus.values()){
if(e.getValue().equals(value)){
include = true;
break;
}
}
return include;
}
}
@@ -0,0 +1,74 @@
package com.mgm.mcrm.apigateway.common.enums;
/**
* 枚举HttpMethods方法
*
* @author Anka
*/
public enum HttpMethods {
/**
* 求获取Request-URI所标识的资源
*/
GET(0, "GET"),
/**
* 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。
* POST请求可能会导致新的资源的建立和/或已有资源的修改
*/
POST(1, "POST"),
/**
* 向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。
* 这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息
* 只获取响应信息报头
*/
HEAD(2, "HEAD"),
/**
* 向指定资源位置上传其最新内容(全部更新,操作幂等)
*/
PUT (3, "PUT"),
/**
* 请求服务器删除Request-URI所标识的资源
*/
DELETE (4, "DELETE"),
/**
* 请求服务器回送收到的请求信息,主要用于测试或诊断
*/
TRACE(5, "TRACE"),
/**
* 向指定资源位置上传其最新内容(部分更新,非幂等)
*/
PATCH (6, "PATCH"),
/**
* 返回服务器针对特定资源所支持的HTTP请求方法。
* 也可以利用向Web服务器发送'*'的请求来测试服务器的功能性
*/
OPTIONS (7, "OPTIONS"),
// /**
// * HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
// */
// CONNECT(99, "CONNECT"),
;
private int code;
private String name;
private HttpMethods(int code, String name){
this.code = code;
this.name = name;
}
public String getName() {
return name;
}
public int getCode() {
return code;
}
}
@@ -0,0 +1,8 @@
package com.mgm.mcrm.apigateway.common.exception;
public class NoAccessException extends RuntimeException {
public NoAccessException(String message) {
super(message);
}
}
@@ -0,0 +1,46 @@
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;
}
}
@@ -0,0 +1,310 @@
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;
}
}
@@ -0,0 +1,697 @@
package com.mgm.mcrm.apigateway.common.httpclient;
import com.mgm.mcrm.apigateway.common.config.HttpHeader;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.message.BasicHeader;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* http 发送参数
*
* @author Aaka
*/
public class HttpHeaderBuilder {
private HttpHeaderBuilder() {};
public static HttpHeaderBuilder custom() {
return new HttpHeaderBuilder();
}
//记录head头信息
private Map<String, Header> headerMaps = new HashMap<String, Header>();
/**
* 自定义header头信息
*
* @param key header-key
* @param value header-value
* @return 返回当前对象
*/
public HttpHeaderBuilder other(String key, String value) {
headerMaps.put(key, new BasicHeader(key, value));
return this;
}
/**
* 指定客户端能够接收的内容类型
* 例如:Accept: text/plain, text/html
*
* @param accept accept
* @return 返回当前对象
*/
public HttpHeaderBuilder accept(String accept) {
headerMaps.put(HttpReqHead.ACCEPT,
new BasicHeader(HttpReqHead.ACCEPT, accept));
return this;
}
/**
* 浏览器可以接受的字符编码集
* 例如:Accept-Charset: iso-8859-5
*
* @param acceptCharset accept-charset
* @return 返回当前对象
*/
public HttpHeaderBuilder acceptCharset(String acceptCharset) {
headerMaps.put(HttpReqHead.ACCEPT_CHARSET,
new BasicHeader(HttpReqHead.ACCEPT_CHARSET, acceptCharset));
return this;
}
/**
* 指定浏览器可以支持的web服务器返回内容压缩编码类型
* 例如:Accept-Encoding: compress, gzip
*
* @param acceptEncoding accept-encoding
* @return 返回当前对象
*/
public HttpHeaderBuilder acceptEncoding(String acceptEncoding) {
headerMaps.put(HttpReqHead.ACCEPT_ENCODING,
new BasicHeader(HttpReqHead.ACCEPT_ENCODING, acceptEncoding));
return this;
}
/**
* 浏览器可接受的语言
* 例如:Accept-Language: en,zh
*
* @param acceptLanguage accept-language
* @return 返回当前对象
*/
public HttpHeaderBuilder acceptLanguage(String acceptLanguage) {
headerMaps.put(HttpReqHead.ACCEPT_LANGUAGE,
new BasicHeader(HttpReqHead.ACCEPT_LANGUAGE, acceptLanguage));
return this;
}
/**
* 可以请求网页实体的一个或者多个子范围字段
* 例如:Accept-Ranges: bytes
*
* @param acceptRanges accept-ranges
* @return 返回当前对象
*/
public HttpHeaderBuilder acceptRanges(String acceptRanges) {
headerMaps.put(HttpReqHead.ACCEPT_RANGES,
new BasicHeader(HttpReqHead.ACCEPT_RANGES, acceptRanges));
return this;
}
/**
* HTTP授权的授权证书
* 例如:Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
*
* @param authorization authorization
* @return 返回当前对象
*/
public HttpHeaderBuilder authorization(String authorization) {
headerMaps.put(HttpReqHead.AUTHORIZATION,
new BasicHeader(HttpReqHead.AUTHORIZATION, authorization));
return this;
}
public HttpHeaderBuilder ac_property_id(String ac_property_id) {
headerMaps.put(HttpReqHead.AC_PROPERTY_ID,
new BasicHeader(HttpReqHead.AC_PROPERTY_ID, ac_property_id));
return this;
}
/**
* 指定请求和响应遵循的缓存机制
* 例如:Cache-Control: no-cache
*
* @param cacheControl cache-control
* @return 返回当前对象
*/
public HttpHeaderBuilder cacheControl(String cacheControl) {
headerMaps.put(HttpReqHead.CACHE_CONTROL,
new BasicHeader(HttpReqHead.CACHE_CONTROL, cacheControl));
return this;
}
/**
* 表示是否需要持久连接(HTTP 1.1默认进行持久连接)
* 例如:Connection: close 短链接; Connection: keep-alive 长连接
*
* @param connection connection
* @return 返回当前对象
*/
public HttpHeaderBuilder connection(String connection) {
headerMaps.put(HttpReqHead.CONNECTION,
new BasicHeader(HttpReqHead.CONNECTION, connection));
return this;
}
/**
* HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器
* 例如:Cookie: $Version=1; Skin=new;
*
* @param cookie cookie
* @return 返回当前对象
*/
public HttpHeaderBuilder cookie(String cookie) {
headerMaps.put(HttpReqHead.COOKIE,
new BasicHeader(HttpReqHead.COOKIE, cookie));
return this;
}
/**
* 请求内容长度
* 例如:Content-Length: 348
*
* @param contentLength content-length
* @return 返回当前对象
*/
public HttpHeaderBuilder contentLength(String contentLength) {
headerMaps.put(HttpReqHead.CONTENT_LENGTH,
new BasicHeader(HttpReqHead.CONTENT_LENGTH, contentLength));
return this;
}
/**
* 请求的与实体对应的MIME信息
* 例如:Content-Type: application/x-www-form-urlencoded
*
* @param contentType content-type
* @return 返回当前对象
*/
public HttpHeaderBuilder contentType(String contentType) {
headerMaps.put(HttpReqHead.CONTENT_TYPE,
new BasicHeader(HttpReqHead.CONTENT_TYPE, contentType));
return this;
}
/**
* 请求发送的日期和时间
* 例如:Date: Tue, 15 Nov 2010 08:12:31 GMT
*
* @param date date
* @return 返回当前对象
*/
public HttpHeaderBuilder date(String date) {
headerMaps.put(HttpReqHead.DATE,
new BasicHeader(HttpReqHead.DATE, date));
return this;
}
/**
* 请求的特定的服务器行为
* 例如:Expect: 100-continue
*
* @param expect expect
* @return 返回当前对象
*/
public HttpHeaderBuilder expect(String expect) {
headerMaps.put(HttpReqHead.EXPECT,
new BasicHeader(HttpReqHead.EXPECT, expect));
return this;
}
/**
* 发出请求的用户的Email
* 例如:From: user@email.com
*
* @param from from
* @return 返回当前对象
*/
public HttpHeaderBuilder from(String from) {
headerMaps.put(HttpReqHead.FROM,
new BasicHeader(HttpReqHead.FROM, from));
return this;
}
/**
* 指定请求的服务器的域名和端口号
* 例如:Host: blog.csdn.net
*
* @param host host
* @return 返回当前对象
*/
public HttpHeaderBuilder host(String host) {
headerMaps.put(HttpReqHead.HOST,
new BasicHeader(HttpReqHead.HOST, host));
return this;
}
/**
* 只有请求内容与实体相匹配才有效
* 例如:If-Match: “737060cd8c284d8af7ad3082f209582d”
*
* @param ifMatch if-match
* @return 返回当前对象
*/
public HttpHeaderBuilder ifMatch(String ifMatch) {
headerMaps.put(HttpReqHead.IF_MATCH,
new BasicHeader(HttpReqHead.IF_MATCH, ifMatch));
return this;
}
/**
* 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码
* 例如:If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT
*
* @param ifModifiedSince if-modified-Since
* @return 返回当前对象
*/
public HttpHeaderBuilder ifModifiedSince(String ifModifiedSince) {
headerMaps.put(HttpReqHead.IF_MODIFIED_SINCE,
new BasicHeader(HttpReqHead.IF_MODIFIED_SINCE, ifModifiedSince));
return this;
}
/**
* 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变
* 例如:If-None-Match: “737060cd8c284d8af7ad3082f209582d”
*
* @param ifNoneMatch if-none-match
* @return 返回当前对象
*/
public HttpHeaderBuilder ifNoneMatch(String ifNoneMatch) {
headerMaps.put(HttpReqHead.IF_NONE_MATCH,
new BasicHeader(HttpReqHead.IF_NONE_MATCH, ifNoneMatch));
return this;
}
/**
* 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag
* 例如:If-Range: “737060cd8c284d8af7ad3082f209582d”
*
* @param ifRange if-range
* @return 返回当前对象
*/
public HttpHeaderBuilder ifRange(String ifRange) {
headerMaps.put(HttpReqHead.IF_RANGE,
new BasicHeader(HttpReqHead.IF_RANGE, ifRange));
return this;
}
/**
* 只在实体在指定时间之后未被修改才请求成功
* 例如:If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT
*
* @param ifUnmodifiedSince if-unmodified-since
* @return 返回当前对象
*/
public HttpHeaderBuilder ifUnmodifiedSince(String ifUnmodifiedSince) {
headerMaps.put(HttpReqHead.IF_UNMODIFIED_SINCE,
new BasicHeader(HttpReqHead.IF_UNMODIFIED_SINCE, ifUnmodifiedSince));
return this;
}
/**
* 限制信息通过代理和网关传送的时间
* 例如:Max-Forwards: 10
*
* @param maxForwards max-forwards
* @return 返回当前对象
*/
public HttpHeaderBuilder maxForwards(String maxForwards) {
headerMaps.put(HttpReqHead.MAX_FORWARDS,
new BasicHeader(HttpReqHead.MAX_FORWARDS, maxForwards));
return this;
}
/**
* 用来包含实现特定的指令
* 例如:Pragma: no-cache
*
* @param pragma pragma
* @return 返回当前对象
*/
public HttpHeaderBuilder pragma(String pragma) {
headerMaps.put(HttpReqHead.PRAGMA,
new BasicHeader(HttpReqHead.PRAGMA, pragma));
return this;
}
/**
* 连接到代理的授权证书
* 例如:Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
*
* @param proxyAuthorization proxy-authorization
* @return 返回当前对象
*/
public HttpHeaderBuilder proxyAuthorization(String proxyAuthorization) {
headerMaps.put(HttpReqHead.PROXY_AUTHORIZATION,
new BasicHeader(HttpReqHead.PROXY_AUTHORIZATION, proxyAuthorization));
return this;
}
/**
* 只请求实体的一部分,指定范围
* 例如:Range: bytes=500-999
*
* @param range range
* @return 返回当前对象
*/
public HttpHeaderBuilder range(String range) {
headerMaps.put(HttpReqHead.RANGE,
new BasicHeader(HttpReqHead.RANGE, range));
return this;
}
/**
* 先前网页的地址,当前请求网页紧随其后,即来路
* 例如:Referer: http://www.zcmhi.com/archives/71.html
*
* @param referer referer
* @return 返回当前对象
*/
public HttpHeaderBuilder referer(String referer) {
headerMaps.put(HttpReqHead.REFERER,
new BasicHeader(HttpReqHead.REFERER, referer));
return this;
}
/**
* 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息
* 例如:TE: trailers,deflate;q=0.5
*
* @param te te
* @return 返回当前对象
*/
public HttpHeaderBuilder te(String te) {
headerMaps.put(HttpReqHead.TE,
new BasicHeader(HttpReqHead.TE, te));
return this;
}
/**
* 向服务器指定某种传输协议以便服务器进行转换(如果支持)
* 例如:Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
*
* @param upgrade upgrade
* @return 返回当前对象
*/
public HttpHeaderBuilder upgrade(String upgrade) {
headerMaps.put(HttpReqHead.UPGRADE,
new BasicHeader(HttpReqHead.UPGRADE, upgrade));
return this;
}
/**
* User-Agent的内容包含发出请求的用户信息
*
* @param userAgent user-agent
* @return 返回当前对象
*/
public HttpHeaderBuilder userAgent(String userAgent) {
headerMaps.put(HttpReqHead.USER_AGENT,
new BasicHeader(HttpReqHead.USER_AGENT, userAgent));
return this;
}
/**
* 关于消息实体的警告信息
* 例如:Warn: 199 Miscellaneous warning
*
* @param warning warning
* @return 返回当前对象
*/
public HttpHeaderBuilder warning(String warning) {
headerMaps.put(HttpReqHead.WARNING,
new BasicHeader(HttpReqHead.WARNING, warning));
return this;
}
/**
* 通知中间网关或代理服务器地址,通信协议
* 例如:Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
*
* @param via via
* @return 返回当前对象
*/
public HttpHeaderBuilder via(String via) {
headerMaps.put(HttpReqHead.VIA,
new BasicHeader(HttpReqHead.VIA, via));
return this;
}
/**
* 设置此HTTP连接的持续时间(超时时间)
* 例如:Keep-Alive: 300
*
* @param keepAlive keep-alive
* @return 返回当前对象
*/
public HttpHeaderBuilder keepAlive(String keepAlive) {
headerMaps.put(HttpReqHead.KEEP_ALIVE,
new BasicHeader(HttpReqHead.KEEP_ALIVE, keepAlive));
return this;
}
public String accept() {
return get(HttpReqHead.ACCEPT);
}
public String acceptCharset() {
return get(HttpReqHead.ACCEPT_CHARSET);
}
public String acceptEncoding() {
return get(HttpReqHead.ACCEPT_ENCODING);
}
public String acceptLanguage() {
return get(HttpReqHead.ACCEPT_LANGUAGE);
}
public String acceptRanges() {
return get(HttpReqHead.ACCEPT_RANGES);
}
public String authorization() {
return get(HttpReqHead.AUTHORIZATION);
}
public String cacheControl() {
return get(HttpReqHead.CACHE_CONTROL);
}
public String connection() {
return get(HttpReqHead.CONNECTION);
}
public String cookie() {
return get(HttpReqHead.COOKIE);
}
public String contentLength() {
return get(HttpReqHead.CONTENT_LENGTH);
}
public String contentType() {
return get(HttpReqHead.CONTENT_TYPE);
}
public String date() {
return get(HttpReqHead.DATE);
}
public String expect() {
return get(HttpReqHead.EXPECT);
}
public String from() {
return get(HttpReqHead.FROM);
}
public String host() {
return get(HttpReqHead.HOST);
}
public String ifMatch() {
return get(HttpReqHead.IF_MATCH);
}
public String ifModifiedSince() {
return get(HttpReqHead.IF_MODIFIED_SINCE);
}
public String ifNoneMatch() {
return get(HttpReqHead.IF_NONE_MATCH);
}
public String ifRange() {
return get(HttpReqHead.IF_RANGE);
}
public String ifUnmodifiedSince() {
return get(HttpReqHead.IF_UNMODIFIED_SINCE);
}
public String maxForwards() {
return get(HttpReqHead.MAX_FORWARDS);
}
public String pragma() {
return get(HttpReqHead.PRAGMA);
}
public String proxyAuthorization() {
return get(HttpReqHead.PROXY_AUTHORIZATION);
}
public String referer() {
return get(HttpReqHead.REFERER);
}
public String te() {
return get(HttpReqHead.TE);
}
public String upgrade() {
return get(HttpReqHead.UPGRADE);
}
public String userAgent() {
return get(HttpReqHead.USER_AGENT);
}
public String via() {
return get(HttpReqHead.VIA);
}
public String warning() {
return get(HttpReqHead.WARNING);
}
public String keepAlive() {
return get(HttpReqHead.KEEP_ALIVE);
}
/**
* 获取head信息
*
* @return
*/
private String get(String headName) {
if (headerMaps.containsKey(headName)) {
return headerMaps.get(headName).getValue();
}
return null;
}
/**
* 返回header头信息
*
* @return 返回构建的header头信息数组
*/
public Header[] build() {
Header[] headers = new Header[headerMaps.size()];
int i = 0;
for (Header header : headerMaps.values()) {
headers[i] = header;
i++;
}
headerMaps.clear();
headerMaps = null;
return headers;
}
/**
* Http头信息
*
* @author arron
* @date 2015年11月9日 上午11:29:04
* @version 1.0
*/
private static class HttpReqHead {
public static final String ACCEPT = "Accept";
public static final String ACCEPT_CHARSET = "Accept-Charset";
public static final String ACCEPT_ENCODING = "Accept-Encoding";
public static final String ACCEPT_LANGUAGE = "Accept-Language";
public static final String ACCEPT_RANGES = "Accept-Ranges";
public static final String AUTHORIZATION = "Authorization";
public static final String AC_PROPERTY_ID = "AC-Property-Id";
public static final String CACHE_CONTROL = "Cache-Control";
public static final String CONNECTION = "Connection";
public static final String COOKIE = "Cookie";
public static final String CONTENT_LENGTH = "Content-Length";
public static final String CONTENT_TYPE = "Content-Type";
public static final String DATE= "Date";
public static final String EXPECT = "Expect";
public static final String FROM = "From";
public static final String HOST = "Host";
public static final String IF_MATCH = "If-Match";
public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
public static final String IF_NONE_MATCH = "If-None-Match";
public static final String IF_RANGE = "If-Range";
public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
public static final String KEEP_ALIVE = "Keep-Alive";
public static final String MAX_FORWARDS = "Max-Forwards";
public static final String PRAGMA = "Pragma";
public static final String PROXY_AUTHORIZATION = "Proxy-Authorization";
public static final String RANGE = "Range";
public static final String REFERER = "Referer";
public static final String TE = "TE";
public static final String UPGRADE = "Upgrade";
public static final String USER_AGENT = "User-Agent";
public static final String VIA = "Via";
public static final String WARNING = "Warning";
}
/**
* 常用头信息配置
*
* @author arron
* @version 1.0
*/
public static class Headers{
public static final String APP_FORM_URLENCODED="application/x-www-form-urlencoded";
public static final String TEXT_PLAIN="text/plain";
public static final String TEXT_HTML="text/html";
public static final String TEXT_XML="text/xml";
public static final String TEXT_JSON="text/json";
public static final String CONTENT_CHARSET_ISO_8859_1 = StandardCharsets.ISO_8859_1.name();
public static final String CONTENT_CHARSET_UTF8 = StandardCharsets.UTF_8.name();
public static final String DEF_PROTOCOL_CHARSET = StandardCharsets.US_ASCII.name();
public static final String CONN_CLOSE = "close";
public static final String KEEP_ALIVE = "keep-alive";
public static final String EXPECT_CONTINUE = "100-continue";
}
public static Map<String, String> getDefaultHeaders(URLConnection connection) {
Map<String, String> defaultHeaders = new HashMap<>();
defaultHeaders.put(HttpHeader.ACCEPT, "*/*");
defaultHeaders.put(HttpHeader.CONNECTION, "Keep-Alive");
defaultHeaders.put(HttpHeader.USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
defaultHeaders.put(HttpHeader.ACCEPT_CHARSET, "utf-8");
return defaultHeaders;
}
/**
* 設置請求頭到連接對象
*
* @param conn URL連接對象
* @param contentType 內容類型
* @param headers HTTP 請求頭 Map(可選,如果為 null 或空則使用默認值)
*/
public static void setRequestHeaders(URLConnection conn, String contentType, Map<String, String> headers) {
Map<String, String> defaultHeaders = getDefaultHeaders(conn);
// 如果傳入了自定義 headers,則合併(自定義的優先)
if (headers != null && !headers.isEmpty()) {
defaultHeaders.putAll(headers);
}
// 設置所有請求頭
for (Map.Entry<String, String> entry : defaultHeaders.entrySet()) {
conn.setRequestProperty(entry.getKey(), entry.getValue());
}
// Content-Type 優先級最高,如果指定了則覆蓋
if (contentType != null) {
conn.setRequestProperty("Content-Type", contentType);
}
}
}
@@ -0,0 +1,72 @@
package com.mgm.mcrm.apigateway.common.httpclient;
import com.alibaba.fastjson.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);
}
}
}
@@ -0,0 +1,375 @@
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;
}
}
@@ -0,0 +1,197 @@
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);
}
}
}
@@ -0,0 +1,33 @@
package com.mgm.mcrm.apigateway.common.listener;
import com.mgm.mcrm.apigateway.allotment.services.RoomCriteriaDaylightService;
import com.mgm.mcrm.apigateway.common.constants.SysCommon;
import com.mgm.mcrm.apigateway.daylight.webhook.eventhandlers.impl.AvailableRoomCountUpdatedHandler;
import com.mgm.mcrm.apigateway.daylight.webhook.eventhandlers.impl.ReservationNotificationHandler;
import com.mgm.mcrm.apigateway.daylight.webhook.eventhandlers.impl.RoomTypeDateAvailabilityChangedHandler;
import com.mgm.mcrm.apigateway.daylight.webhook.services.DaylightWebhookFactory;
import com.mgm.mcrm.apigateway.reservation.services.BookingService;
import jakarta.annotation.Resource;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class ConfigListener implements ApplicationListener<ApplicationStartedEvent> {
@Resource
private RoomCriteriaDaylightService roomCriteriaDaylightService;
@Resource
private BookingService bookingService;
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
SysCommon.initRuntimePath();
//--Register Allotment handlers
DaylightWebhookFactory.registerHandler("RoomTypeDateAvailabilityChanged", new RoomTypeDateAvailabilityChangedHandler(roomCriteriaDaylightService));
DaylightWebhookFactory.registerHandler("AvailableRoomCountUpdated", new AvailableRoomCountUpdatedHandler(roomCriteriaDaylightService));
//--Register Reservation Notification handlers
DaylightWebhookFactory.registerHandler("ReservationNotification", new ReservationNotificationHandler(bookingService));
}
}
@@ -0,0 +1,169 @@
package com.mgm.mcrm.apigateway.common.utils;
import org.apache.commons.lang3.StringUtils;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;
public class DateTimeUtil {
public static LocalDateTime getDateFromString(String dateTimeValue, String dateFormat) {
if (StringUtils.isBlank(dateTimeValue)) {
return null;
}
try {
DateTimeFormatter dtFormat = DateTimeFormatter.ofPattern(dateFormat);
// 根据格式判断是纯日期还是包含时间
if (dateFormat.contains("HH") || dateFormat.contains("mm") || dateFormat.contains("ss")) {
// 包含时间格式,使用LocalDateTime解析
return LocalDateTime.parse(dateTimeValue, dtFormat);
} else {
// 纯日期格式,使用LocalDate解析后转换为LocalDateTime
LocalDate localDate = LocalDate.parse(dateTimeValue, dtFormat);
return localDate.atStartOfDay(); // 设置为当天的00:00:00
}
} catch (Exception e) {
System.err.println("日期解析失败: " + e.getMessage());
return null;
}
}
public static String getDateByFormat(LocalDateTime dtDateTime, String strFormat) {
String returnDate = null;
if (dtDateTime != null) {
try {
DateTimeFormatter dtFormat = DateTimeFormatter.ofPattern(strFormat);
returnDate = dtDateTime.format(dtFormat);
} catch (RuntimeException ignored) {
}
}
return returnDate;
}
public static String getCurrentDate(String strFormat) {
return getDateByFormat(LocalDateTime.now(), strFormat);
}
public static LocalDateTime getCurrentDateTime(String strFormat) {
LocalDateTime returnDate = null;
try {
DateTimeFormatter dtFormat = DateTimeFormatter.ofPattern(strFormat);
String dateTimeValue = getDateByFormat(LocalDateTime.now(), strFormat);
returnDate = LocalDateTime.parse(dateTimeValue,dtFormat);
} catch (Exception ignored) {
}
return returnDate;
}
public static LocalDateTime addDay(LocalDateTime currdate,long days) {
return currdate.plusDays(days);
}
public static String getDateByFormatUseTimeStamp(Long timeStamp, String strFormat) {
String returnDate = null;
if (timeStamp != null) {
try {
SimpleDateFormat formatter;
formatter = new SimpleDateFormat(strFormat);
returnDate = formatter.format(timeStamp);
} catch (Exception err) {
}
}
return returnDate;
}
public static String getDiffDate(LocalDateTime DateStart, LocalDateTime DateEnd, String dateType) {
String returnDate = null;
try {
Duration duration = Duration.between(DateStart, DateEnd);
//long diffTime = DateEnd.getTime() - DateStart.getTime();
if("day".equalsIgnoreCase(dateType)) {
long days = duration.toDays();
returnDate = Long.toString(days);
}else if("hour".equalsIgnoreCase(dateType)) {
long hours = duration.toHours();
returnDate = Long.toString(hours);
}else { //minute
long minutes = duration.toMinutes();
returnDate = Long.toString(minutes);
}
} catch (Exception err) {
}
return returnDate;
}
public static boolean isValidDate(String dateStr) {
try {
dateStr=dateStr.split(" ")[0];
String[] parts = dateStr.split("-");
int year = Integer.parseInt(parts[0]);
int month = Integer.parseInt(parts[1]);
int day = Integer.parseInt(parts[2]);
if (month < 1 || month > 12) {
return false;
}
YearMonth yearMonth = YearMonth.of(year, month);
int maxDay = yearMonth.lengthOfMonth();
boolean isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
if (month == 2 && isLeapYear) {
maxDay = 29;
} else if (month == 2) {
maxDay = 28;
}
if (day < 1 || day > maxDay) {
return false;
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate.parse(dateStr, formatter);
return true;
} catch (DateTimeParseException e) {
return false;
}
}
public static long fromDateStringToLong(String inVal) {
LocalDateTime date = null;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss:SSS");
try {
date = LocalDateTime.parse(inVal,formatter);
} catch (Exception e) {
e.printStackTrace();
}
return date!=null?date.toEpochSecond(ZoneOffset.UTC):0;
}
public static long getTimeSpanSSS(LocalDateTime startDate, LocalDateTime endDate) {
DateTimeFormatter timeFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss:SSS");
String startStr = timeFormat.format(startDate);
String endStr = timeFormat.format(endDate);
long startMS = fromDateStringToLong(startStr);
long endMS = fromDateStringToLong(endStr);
long returnMS = endMS-startMS;
return returnMS;
}
}
@@ -0,0 +1,68 @@
package com.mgm.mcrm.apigateway.common.utils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
public class LogUtil {
private static String loggerName = LogUtil.class.getName();
private static Logger logger = LoggerFactory.getLogger(loggerName);
public static Logger getLogger(Class callClass){
try
{
logger = LoggerFactory.getLogger(callClass.getName());
}catch(Exception err){
loggerName = LogUtil.class.getName();
logger = LoggerFactory.getLogger(loggerName);
}
return logger;
}
public static void info(Class callClass,String message) {
getLogger(callClass).info(message);
}
public static void warn(Class callClass,String message) {
getLogger(callClass).warn(message);
}
public static void error(Class callClass,String message) {
getLogger(callClass).error(message);
}
public static String getObjectAttr(Object srcObj, String[] attrNames) {
String attrText = "";
if(srcObj!=null && attrNames!=null) {
try {
JSONObject jsonObject = (JSONObject)JSONObject.toJSON(srcObj);
for(String attr:attrNames) {
attrText+=(attr+"=");
if(jsonObject.containsKey(attr)) {
attrText+=jsonObject.getString(attr);
}
attrText+=";";
}
}catch(Exception ignored) {
}
}
return attrText;
}
public static String getFormatLog(String operationTag, String dataTag, boolean isSuccess, String resultTag,String message) {
String logMessage = "";
String statusMsg = (resultTag==null?"":resultTag);
String errorMsg = (message==null?"":message);
logMessage = operationTag+(StringUtils.isBlank(dataTag)?"":" ["+dataTag+"]");
if(isSuccess) {
logMessage += (" successed" + (StringUtils.isBlank(statusMsg)?"":" with ["+statusMsg+"]"));
}else {
logMessage += (" failed with error ["+errorMsg+"]");
}
return logMessage;
}
}
@@ -0,0 +1,355 @@
package com.mgm.mcrm.apigateway.common.utils;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.mgm.mcrm.apigateway.common.constants.SysCommon;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.springframework.web.util.UriUtils;
public class NetworkUtil {
private static final List<String> interalIpPatterns = new ArrayList<String>();
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]?)$");
private static final List<String> INTERNAL_IP_PREFIXES = Arrays.asList(
"10.", "192.168.", "172.16.", "172.17.", "172.18.", "172.19.",
"172.20.", "172.21.", "172.22.", "172.23.", "172.24.", "172.25.",
"172.26.", "172.27.", "172.28.", "172.29.", "172.30.", "172.31."
);
public static void setInternalIpPattern(String patternConfig) {
interalIpPatterns.clear();
String[] patternItems = patternConfig.split(";");
for(String pItem:patternItems) {
String pVal = pItem.trim();
if(StringUtils.isNotBlank(patternConfig)) {
interalIpPatterns.add(pVal);
}
}
}
public static boolean isMatchInternal(String ipContent) {
boolean internalFlag = false;
if(StringUtils.isNotBlank(ipContent) && !interalIpPatterns.isEmpty()) {
String ipPart = "\\b(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\b";
for(String ipItem:interalIpPatterns) {
if(ipItem.contains("*")) {
String itemPattern = ipItem.replace(".", "\\.");
itemPattern = itemPattern.replace("*", ipPart);
Pattern pt = Pattern.compile(itemPattern);
Matcher mt = pt.matcher(ipContent);
if(mt.find()) {
internalFlag=true;
break;
}
}else {
if(ipContent.contains(ipItem)) {
internalFlag=true;
break;
}
}
}
}
return internalFlag;
}
/**
* Gets the client ip addr.
*
* @param request the request
* @return the client ip addr
*/
public static String getClientIpAddr(HttpServletRequest request) {
String ip = getIpFromHeaders(request);
if(ip==null){
ip = request.getRemoteAddr();
}
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
}
private static String getIpFromHeaders(HttpServletRequest request) {
String[] headerNames = {
"X-Real-IP",
"X-Forwarded-For",
"Proxy-Client-IP",
"WL-Proxy-Client-IP",
"HTTP_CLIENT_IP",
"HTTP_X_FORWARDED_FOR"
};
boolean isContainForwardHeader=false;
for (String headerName : headerNames) {
String headerValue = request.getHeader(headerName);
if (headerValue != null && !headerValue.isEmpty()) {
isContainForwardHeader=true;
//LogUtil.info(NetworkUtil.class,"Check header["+headerName+"] of value["+headerValue+"]");
String ip = extractValidIp(headerValue);
if (ip != null) {
return ip;
}
}
}
return (isContainForwardHeader?"INVALID_IP":null);
}
private static String extractValidIp(String headerValue) {
if (headerValue.contains(",")) {
String[] ips = headerValue.split(",");
for(int i=ips.length-1;i>=0;i--){
String ip = ips[i].trim();
if (isValidPublicIp(ip)) {
return ip;
}
}
return isValidIp(ips[ips.length - 1].trim())?ips[ips.length - 1].trim():null;
} else {
String ip = headerValue.trim();
return isValidIp(ip) ? ip : null;
}
}
private static boolean isValidPublicIp(String ip) {
return isValidIp(ip) && !isInternalIp(ip);
}
private static boolean isValidIp(String ip) {
return ip != null && !ip.isEmpty() &&
!"unknown".equalsIgnoreCase(ip) &&
IPV4_PATTERN.matcher(ip).matches();
}
private static boolean isInternalIp(String ip) {
if (ip == null) return false;
if (ip.equals("127.0.0.1") || ip.equals("0:0:0:0:0:0:0:1")) {
return true;
}
for (String prefix : INTERNAL_IP_PREFIXES) {
if (ip.startsWith(prefix)) {
return true;
}
}
return false;
}
/**
* Gets the real ips.
*
* @return the real ips
*/
public static List<String> getRealIps() {
List<String> ips = new ArrayList<String>();
String localip = null;// 本地IP,如果没有配置外网IP则返回它
String netip = null;// 外网IP
Enumeration<NetworkInterface> netInterfaces;
try {
netInterfaces = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
return null;
}
InetAddress ip = null;
boolean finded = false;// 是否找到外网IP
while (netInterfaces.hasMoreElements() && !finded) {
NetworkInterface ni = netInterfaces.nextElement();
Enumeration<InetAddress> address = ni.getInetAddresses();
while (address.hasMoreElements()) {
ip = address.nextElement();
if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && !ip.getHostAddress().contains(":")) {
netip = ip.getHostAddress();
ips.add(netip);
finded = true;
break;
} else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress()
&& !ip.getHostAddress().contains(":")) {// 内网IP
localip = ip.getHostAddress();
ips.add(localip);
}
}
}
return ips;
}
/**
* Gets the real ip.
*
* @return the real ip
*/
public static String getRealIp() {
return getRealIps().iterator().next();
}
/**
* 获取访问者内网IP
*
* @return the server ip
*/
public static String getInternalIp() {
// 本地IP,如果没有配置外网IP则返回它
String localip = null;
// 外网IP
String netip = null;
try {
Enumeration netInterfaces = NetworkInterface.getNetworkInterfaces();
InetAddress ip = null;
// 是否找到外网IP
boolean finded = false;
while (netInterfaces.hasMoreElements() && !finded) {
NetworkInterface ni = (NetworkInterface) netInterfaces.nextElement();
Enumeration address = ni.getInetAddresses();
while (address.hasMoreElements()) {
ip = (InetAddress) address.nextElement();
if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {
// 外网IP
netip = ip.getHostAddress();
finded = true;
break;
} else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress()
&& ip.getHostAddress().indexOf(":") == -1) {
// 内网IP
localip = ip.getHostAddress();
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
if (netip != null && !"".equals(netip)) {
return netip;
} else {
return localip;
}
}
/**
* 判断ip是否在网段cidr内,cidr格式192.168.0.1/255
*
* @return the server ip
*/
public static boolean ipInRange(String ip, String cidr) {
try {
String[] tmp = cidr.split("/");
if (tmp.length > 1) {
String[] ips = ip.split("\\.");
int ipAddr = (Integer.parseInt(ips[0]) << 24) | (Integer.parseInt(ips[1]) << 16)
| (Integer.parseInt(ips[2]) << 8) | Integer.parseInt(ips[3]);
int type = Integer.parseInt(cidr.replaceAll(".*/", ""));
int mask = 0xFFFFFFFF << (32 - type);
String cidrIp = cidr.replaceAll("/.*", "");
String[] cidrIps = cidrIp.split("\\.");
int cidrIpAddr = (Integer.parseInt(cidrIps[0]) << 24) | (Integer.parseInt(cidrIps[1]) << 16)
| (Integer.parseInt(cidrIps[2]) << 8) | Integer.parseInt(cidrIps[3]);
return (ipAddr & mask) == (cidrIpAddr & mask);
} else if (tmp.length == 1 && ip.equals(cidr)) {
return true;
} else {
return false;
}
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
}
public static String getServerName() {
String serverName="";
try {
InetAddress localhost = InetAddress.getLocalHost();
serverName = localhost.getHostName();
} catch (Exception e) {
e.printStackTrace();
}
return serverName;
}
/**
* 判断ip是否在网段cidr内,cidr格式192.168.0.1/255
*
* @return the server ip
*/
public static boolean isMacauIp(String ip,String macauIps) {
try {
String[] cidrArr = StringUtils.split(macauIps,";");
if(cidrArr.length>0) {
for(String cidr : cidrArr) {
String[] tmp = cidr.split("/");
if (tmp.length > 1) {
String[] ips = ip.split("\\.");
try {
Integer.parseInt(ips[0]);
Integer.parseInt(ips[1]);
Integer.parseInt(ips[2]);
Integer.parseInt(ips[3]);
} catch (Exception e) {
continue;
}
int ipAddr = (Integer.parseInt(ips[0]) << 24) | (Integer.parseInt(ips[1]) << 16)
| (Integer.parseInt(ips[2]) << 8) | Integer.parseInt(ips[3]);
int type = Integer.parseInt(cidr.replaceAll(".*/", ""));
int mask = 0xFFFFFFFF << (32 - type);
String cidrIp = cidr.replaceAll("/.*", "");
String[] cidrIps = cidrIp.split("\\.");
int cidrIpAddr = (Integer.parseInt(cidrIps[0]) << 24) | (Integer.parseInt(cidrIps[1]) << 16)
| (Integer.parseInt(cidrIps[2]) << 8) | Integer.parseInt(cidrIps[3]);
if((ipAddr & mask) == (cidrIpAddr & mask)) return true;
} else if (tmp.length == 1 && ip.equals(cidr)) {
return true;
}
}
}else {
return false;
}
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
return false;
}
public static boolean isValidURL(String requestUrl){
try {
URI uri = new URI(requestUrl);
String scheme = uri.getScheme();
String host = uri.getHost();
if(!"https".equals(scheme) && !"http".equals(scheme)) {
return false;
}
if(host.matches("\\d+\\.\\d+\\.\\d+\\.\\d+")) {
return false;
}
return true;
} catch (Exception e) {
return false;
}
}
public static String encodeParaWithSpring(String value) {
if(value==null)
value="";
value= value.replace("\r", "").replace("\n", "");
return UriUtils.encode(value, StandardCharsets.UTF_8);
}
public static String sanitizeHeaderValue(String headerValue) {
return headerValue==null? null :(StringEscapeUtils.escapeJava(
headerValue.replace("\r", "").replace("\n", "")
));
}
public static String encodePathWithSpring(String value) {
if(value==null)
value="";
value= value.replace("\r", "").replace("\n", "");
return UriUtils.encodePath(value, StandardCharsets.UTF_8);
}
}
@@ -0,0 +1,261 @@
package com.mgm.mcrm.apigateway.common.utils.mockup;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mgm.mcrm.apigateway.common.constants.SysCommon;
import com.mgm.mcrm.apigateway.common.utils.LogUtil;
public class HttpUtilMockup {
private static JSONArray mockupConfig=null;
private static JSONArray getMockupConfig() {
if(mockupConfig==null) {
try {
String fileContent = SysCommon.loadResFileContentByPath("/mockup/mgm_api_mockup_def.json",1);
LogUtil.info(HttpUtilMockup.class, "[HttpUtilMockup] config file content length=" + (fileContent == null ? 0 : fileContent.length()) + ", first 100 chars=" + (fileContent == null ? "null" : fileContent.substring(0, Math.min(100, fileContent.length()))));
mockupConfig = JSONArray.parseArray(fileContent);
if(mockupConfig==null) {
LogUtil.error(HttpUtilMockup.class, "[HttpUtilMockup] config parsed to null, using empty array");
mockupConfig = new JSONArray();
} else {
LogUtil.info(HttpUtilMockup.class, "[HttpUtilMockup] config loaded successfully, items count=" + mockupConfig.size());
}
}catch(Exception err) {
LogUtil.error(HttpUtilMockup.class, "[HttpUtilMockup] failed to load config: " + err.getMessage());
mockupConfig = new JSONArray();
}
}
return mockupConfig;
}
public static String findMockResultByLink(String requestLink,String requestContent) {
String result ="";
JSONArray configData = getMockupConfig();
LogUtil.info(HttpUtilMockup.class, "[HttpUtilMockup] findMockResultByLink requestLink=" + requestLink + ", requestContent=" + (requestContent == null ? "" : requestContent.substring(0, Math.min(requestContent.length(), 300))));
LogUtil.info(HttpUtilMockup.class, "[HttpUtilMockup] configData size=" + configData.size());
for(int i=0;i<configData.size();i++) {
JSONObject checkItem = configData.getJSONObject(i);
if(checkItem.containsKey("apiLink") && checkItem.containsKey("resultFiles")) {
String apiLink = checkItem.getString("apiLink");
LogUtil.info(HttpUtilMockup.class, "[HttpUtilMockup] checking apiLink[" + i + "]=" + apiLink + ", contains=" + requestLink.contains(apiLink));
if(requestLink.contains(apiLink)) {
LogUtil.info(HttpUtilMockup.class, "[HttpUtilMockup] MATCHED apiLink=" + apiLink);
JSONObject requestObj = null;
try {
requestObj = JSONObject.parseObject(requestContent);
}catch(Exception err) {
}
int resultIndex =0;
if(checkItem.containsKey("resultIndex")) {
resultIndex=checkItem.getIntValue("resultIndex");
}
LogUtil.info(HttpUtilMockup.class, "[HttpUtilMockup] default resultIndex=" + resultIndex + ", requestObj=" + (requestObj == null ? "null" : requestObj.toJSONString()));
if(checkItem.containsKey("mockupRules") && requestObj!=null) {
JSONArray mockupRules = checkItem.getJSONArray("mockupRules");
if(mockupRules!=null) {
int matchIndex = matchResultByRules(requestObj, mockupRules);
LogUtil.info(HttpUtilMockup.class, "[HttpUtilMockup] matched rule fileIndex=" + matchIndex);
if(matchIndex>=0) {
resultIndex =matchIndex;
}
}
}
if(checkItem.containsKey("resultFiles")) {
JSONArray resultFiles = checkItem.getJSONArray("resultFiles") ;
LogUtil.info(HttpUtilMockup.class, "[HttpUtilMockup] resultFiles size=" + resultFiles.size() + ", resultIndex=" + resultIndex);
if(resultFiles!=null && resultIndex<resultFiles.size()) {
String dataFile = resultFiles.get(resultIndex).toString();
LogUtil.info(HttpUtilMockup.class, "[HttpUtilMockup] loading mock file: " + dataFile);
result = SysCommon.loadResFileContentByPath(dataFile, 1);
LogUtil.info(HttpUtilMockup.class, "[HttpUtilMockup] mock file content length=" + (result == null ? 0 : result.length()));
}
}
break;
}
}
}
return result;
}
private static int matchResultByRules(JSONObject requestObj, JSONArray mockupRules) {
int matchIndex =-1;
for(int i=0;i<mockupRules.size();i++) {
JSONObject ruleItem = mockupRules.getJSONObject(i);
if(ruleItem.containsKey("condiction")) {
boolean isMatch = matchCondiction(requestObj, ruleItem.getString("condiction"));
if(isMatch==true) {
matchIndex =ruleItem.getIntValue("fileIndex");
break;
}
}
}
return matchIndex;
}
private static boolean matchCondiction(JSONObject requestObj, String condiction) {
boolean matchResult = false;
List<String> operateList = new ArrayList<String>();
String[] andList = condiction.split("&&");
for(int i=0;i<andList.length;i++) {
if(i>0) {
operateList.add("&&");
}
operateList.add(andList[i].trim());
}
for(int i=0;i<operateList.size();i++) {
String val = operateList.get(i);
if(!val.equals("&&") && val.contains("||")) {
String[] orList = val.split("\\|\\|");
for(int j=0;j<orList.length;j++) {
if(j>0) {
operateList.add(i,"||");
i++;
}
if(j==0) {
operateList.set(i, orList[j].trim());
i++;
}else {
operateList.add(i, orList[j].trim());
i++;
}
}
}
}
String lastOperate = "AND";
boolean isFirst =true;
for(int i=0;i<operateList.size();i++) {
String express = operateList.get(i);
if(express.equals("&&")) {
lastOperate = "AND";
}else if(express.equals("||")) {
lastOperate = "OR";
}else {
boolean valRes = calcCondictionValue(requestObj, express);
if(isFirst==true) {
matchResult=matchResult||valRes;
isFirst=false;
}else {
if(lastOperate.equals("AND")) {
matchResult=matchResult&&valRes;
}else {
matchResult=matchResult||valRes;
}
}
}
}
return matchResult;
}
private static boolean calcCondictionValue(JSONObject requestObj, String express) {
boolean result = false;
String valName1="";
String valName2="";
String operate="";
if(express.indexOf("==")>0) {
int operIndex = express.indexOf("==");
operate="==";
valName1 = express.substring(0, operIndex).trim();
valName2 =express.substring(operIndex+2).trim();
}else if(express.indexOf(">=")>0) {
int operIndex = express.indexOf(">=");
operate=">=";
valName1 = express.substring(0, operIndex).trim();
valName2 =express.substring(operIndex+2).trim();
}else if(express.indexOf("<=")>0) {
int operIndex = express.indexOf("<=");
operate="<=";
valName1 = express.substring(0, operIndex).trim();
valName2 =express.substring(operIndex+2).trim();
}else if(express.indexOf(">")>0) {
int operIndex = express.indexOf(">");
operate=">";
valName1 = express.substring(0, operIndex).trim();
valName2 =express.substring(operIndex+1).trim();
}else if(express.indexOf("<")>0) {
int operIndex = express.indexOf("<");
operate="<";
valName1 = express.substring(0, operIndex).trim();
valName2 =express.substring(operIndex+1).trim();
}
if(!operate.isEmpty()) {
double numVal1 =0;
double numVal2 =0;
boolean isNum=true;
if(requestObj.containsKey(valName1)) {
try {
numVal1 = requestObj.getDoubleValue(valName1);
}catch(Exception err) {
isNum=false;
}
}else {
try {
numVal1 = Double.parseDouble(valName1);
}catch(Exception err) {
isNum=false;
}
}
if(isNum==true) {
if(requestObj.containsKey(valName2)) {
try {
numVal2 = requestObj.getDoubleValue(valName2);
}catch(Exception err) {
isNum=false;
}
}else {
try {
numVal2 = Double.parseDouble(valName2);
}catch(Exception err) {
isNum=false;
}
}
}
if(isNum==true) {
if(operate.equals("==")) {
result = (numVal1==numVal2);
}else if(operate.equals("<=")) {
result = (numVal1<=numVal2);
}else if(operate.equals(">=")) {
result = (numVal1>=numVal2);
}else if(operate.equals("<")) {
result = (numVal1<numVal2);
}else if(operate.equals(">")) {
result = (numVal1>numVal2);
}
}else {
String textVal1 = valName1;
String textVal2 = valName2;
if(requestObj.containsKey(valName1)) {
textVal1 = requestObj.getString(valName1);
}
if(requestObj.containsKey(valName2)) {
textVal2 = requestObj.getString(valName2);
}
if(operate.equals("==")) {
result = (textVal1.compareTo(textVal2)==0);
}else if(operate.equals("<=")) {
result = (textVal1.compareTo(textVal2)<=0);
}else if(operate.equals(">=")) {
result = (textVal1.compareTo(textVal2)>=0);
}else if(operate.equals("<")) {
result = (textVal1.compareTo(textVal2)<0);
}else if(operate.equals(">")) {
result = (textVal1.compareTo(textVal2)>0);
}
}
}
return result;
}
public static String processMockRequest(String requestUrl, String requestContent) {
String responseEntity = findMockResultByLink(requestUrl, requestContent);
LogUtil.info(HttpUtilMockup.class, "[HttpUtilMockup] requestUrl=" + requestUrl + " mockResponse=" + (responseEntity == null ? "" : responseEntity.substring(0, Math.min(responseEntity.length(), 200))));
return responseEntity;
}
public static void clearConfigCache() {
mockupConfig = null;
}
}
@@ -0,0 +1,27 @@
package com.mgm.mcrm.apigateway.daylight.common.controllers;
import com.mgm.mcrm.apigateway.common.dtos.BaseApiResponse;
import com.mgm.mcrm.apigateway.daylight.common.services.DaylightFetchConfigurationService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DaylightTestController {
@Resource
private DaylightFetchConfigurationService daylightFetchConfigurationService;
@GetMapping("/test/fetch-daylight-config")
public BaseApiResponse testFetchDaylightConfiguration() {
BaseApiResponse propertiesResponse = daylightFetchConfigurationService.fetchDaylightProperties();
if (!propertiesResponse.isSuccess()) {
return propertiesResponse;
}
BaseApiResponse configResponse = daylightFetchConfigurationService.fetchDaylightConfiguration();
if (!configResponse.isSuccess()) {
return configResponse;
}
return daylightFetchConfigurationService.fetchDaylightBlockCodes();
}
}
@@ -0,0 +1,12 @@
package com.mgm.mcrm.apigateway.daylight.common.dtos;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class CachedToken {
private TokenResponse token;
private LocalDateTime expireTime;
}
@@ -0,0 +1,18 @@
package com.mgm.mcrm.apigateway.daylight.common.dtos;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
@Data
public class TokenResponse {
@JSONField(name = "access_token")
private String accessToken;
@JSONField(name = "expires_in")
private String expiresIn;
@JSONField(name = "token_type")
private String tokenType;
@JSONField(name = "refresh_token")
private String refreshToken;
@JSONField(name = "scope")
private String scope;
}
@@ -0,0 +1,120 @@
package com.mgm.mcrm.apigateway.daylight.common.scheduler;
import com.mgm.mcrm.apigateway.common.dtos.BaseApiResponse;
import com.mgm.mcrm.apigateway.daylight.common.services.DaylightFetchConfigurationService;
import com.mgm.mcrm.apigateway.common.utils.LogUtil;
import com.mgm.mcrm.apigateway.daylight.repositories.CfgDaylightConfigurationDao;
import jakarta.annotation.Resource;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class DaylightConfigurationScheduler {
@Resource
private DaylightFetchConfigurationService daylightFetchConfigurationService;
@Resource
private CfgDaylightConfigurationDao cfgDaylightConfigurationDao;
@Order(1)
@EventListener(ApplicationReadyEvent.class)
public void fetchDaylightPropertiesOnStartupIfMissing() {
LogUtil.info(DaylightConfigurationScheduler.class, "Checking saved Daylight properties on startup");
try {
if (cfgDaylightConfigurationDao.existsSavedDaylightProperties()) {
LogUtil.info(DaylightConfigurationScheduler.class, "Saved Daylight properties found, skip startup fetch");
return;
}
LogUtil.warn(DaylightConfigurationScheduler.class, "No saved Daylight properties found, start startup fetch");
BaseApiResponse propResponse = daylightFetchConfigurationService.fetchDaylightProperties();
if (propResponse.isSuccess()) {
LogUtil.info(DaylightConfigurationScheduler.class, "Startup properties completed: " + propResponse.getMessage());
} else {
LogUtil.warn(DaylightConfigurationScheduler.class, "Startup properties failed: " + propResponse.getMessage());
}
} catch (Exception e) {
LogUtil.error(DaylightConfigurationScheduler.class, "Startup properties check error: " + e.getMessage());
}
}
@Order(2)
@EventListener(ApplicationReadyEvent.class)
public void fetchDaylightConfigurationOnStartupIfMissing() {
LogUtil.info(DaylightConfigurationScheduler.class, "Checking saved Daylight configurations on startup");
try {
BaseApiResponse configResponse = daylightFetchConfigurationService.fetchDaylightConfiguration();
if (configResponse.isSuccess()) {
LogUtil.info(DaylightConfigurationScheduler.class, "Startup configurations completed: " + configResponse.getMessage());
} else {
LogUtil.warn(DaylightConfigurationScheduler.class, "Startup configurations failed: " + configResponse.getMessage());
}
} catch (Exception e) {
LogUtil.error(DaylightConfigurationScheduler.class, "Startup configurations check error: " + e.getMessage());
}
}
@Order(3)
@EventListener(ApplicationReadyEvent.class)
public void fetchDaylightBlockCodesOnStartupIfMissing() {
LogUtil.info(DaylightConfigurationScheduler.class, "Checking saved Daylight block codes on startup");
try {
if (!cfgDaylightConfigurationDao.existsSavedDaylightProperties()) {
LogUtil.info(DaylightConfigurationScheduler.class, "No saved Daylight properties found, skip block codes startup fetch");
return;
}
BaseApiResponse blockResponse = daylightFetchConfigurationService.fetchDaylightBlockCodes();
if (blockResponse.isSuccess()) {
LogUtil.info(DaylightConfigurationScheduler.class, "Startup block codes completed: " + blockResponse.getMessage());
} else {
LogUtil.warn(DaylightConfigurationScheduler.class, "Startup block codes failed: " + blockResponse.getMessage());
}
} catch (Exception e) {
LogUtil.error(DaylightConfigurationScheduler.class, "Startup block codes check error: " + e.getMessage());
}
}
/**
* 每天凌晨2点执行一次,拉取 Daylight 配置数据
*/
@Scheduled(cron = "0 0 2 * * ?")
public void fetchDaylightConfigurationDaily() {
LogUtil.info(DaylightConfigurationScheduler.class, "Start scheduled task: fetchDaylightAllData");
try {
// 1. 拉取 Properties
LogUtil.info(DaylightConfigurationScheduler.class, "Step 1/3: Fetching properties...");
BaseApiResponse propResponse = daylightFetchConfigurationService.fetchDaylightProperties();
if (propResponse.isSuccess()) {
LogUtil.info(DaylightConfigurationScheduler.class, "Properties completed: " + propResponse.getMessage());
} else {
LogUtil.warn(DaylightConfigurationScheduler.class, "Properties failed: " + propResponse.getMessage());
}
// 2. 拉取 Configuration
LogUtil.info(DaylightConfigurationScheduler.class, "Step 2/3: Fetching configurations...");
BaseApiResponse configResponse = daylightFetchConfigurationService.fetchDaylightConfiguration();
if (configResponse.isSuccess()) {
LogUtil.info(DaylightConfigurationScheduler.class, "Configurations completed: " + configResponse.getMessage());
} else {
LogUtil.warn(DaylightConfigurationScheduler.class, "Configurations failed: " + configResponse.getMessage());
}
// 3. 拉取 Block Codes
LogUtil.info(DaylightConfigurationScheduler.class, "Step 3/3: Fetching block codes...");
BaseApiResponse blockResponse = daylightFetchConfigurationService.fetchDaylightBlockCodes();
if (blockResponse.isSuccess()) {
LogUtil.info(DaylightConfigurationScheduler.class, "Block codes completed: " + blockResponse.getMessage());
} else {
LogUtil.warn(DaylightConfigurationScheduler.class, "Block codes failed: " + blockResponse.getMessage());
}
LogUtil.info(DaylightConfigurationScheduler.class, "Scheduled task finished: fetchDaylightAllData");
} catch (Exception e) {
LogUtil.error(DaylightConfigurationScheduler.class, "Scheduled task error: " + e.getMessage());
}
}
}
@@ -0,0 +1,651 @@
package com.mgm.mcrm.apigateway.daylight.common.services;
import com.alibaba.fastjson.JSONObject;
import com.mgm.mcrm.apigateway.basesetting.property.models.CfgProperties;
import com.mgm.mcrm.apigateway.basesetting.property.repositories.PropertyDao;
import com.mgm.mcrm.apigateway.common.dtos.BaseApiResponse;
import com.mgm.mcrm.apigateway.common.dtos.config.DaylightApiSetting;
import com.mgm.mcrm.apigateway.daylight.common.dtos.TokenResponse;
import com.mgm.mcrm.apigateway.daylight.models.CfgDaylightConfiguration;
import com.mgm.mcrm.apigateway.daylight.models.SysLogDaylightConfigurationSync;
import com.mgm.mcrm.apigateway.daylight.repositories.CfgDaylightConfigurationDao;
import com.mgm.mcrm.apigateway.daylight.repositories.SysLogDaylightConfigurationSyncDao;
import com.mgm.mcrm.apigateway.proxy.exception.HttpProxyErrorHandler;
import com.mgm.mcrm.apigateway.proxy.services.WebProxyService;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Service
public class DaylightFetchConfigurationService {
private static final Logger log = LoggerFactory.getLogger(DaylightFetchConfigurationService.class);
private final HttpProxyErrorHandler httpErrorHandler = new HttpProxyErrorHandler();
@Resource
private WebProxyService webProxyService;
@Resource
private DaylightTokenService daylightTokenService;
@Autowired
private DaylightApiSetting daylightApiSetting;
@Resource
private PropertyDao propertyDao;
@Resource
private CfgDaylightConfigurationDao cfgDaylightConfigurationDao;
@Resource
private SysLogDaylightConfigurationSyncDao syncLogDao;
public BaseApiResponse fetchDaylightConfiguration() {
BaseApiResponse response = new BaseApiResponse();
Date syncStartTime = new Date();
try {
TokenResponse daylightApiToken = daylightTokenService.getApiAccessToken();
if (daylightApiToken == null || StringUtils.isBlank(daylightApiToken.getAccessToken())) {
response.setSuccess(false);
response.setMessage("Invoke daylight token failed");
return response;
}
List<CfgProperties> allProperties = propertyDao.findByCategory("DAYLIGHT");
int savedCount = 0;
if (allProperties == null || allProperties.isEmpty()) {
response.setSuccess(false);
response.setMessage("No properties found with category 'DAYLIGHT'");
return response;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
for (CfgProperties property : allProperties) {
String dlPropertyId = property.getDlPropertyId();
if (StringUtils.isBlank(dlPropertyId)) {
continue;
}
// 按每个 property 查询上次成功同步时间
// 注意:仅当 sys_log 有 SUCCESS 日志,且 cfg_daylight_configuration 表中确实存在该 property 的
// 配置数据时,才走增量同步;否则强制走全量同步,避免数据空缺时漏掉 configType
String updatedAtParam = "";
Optional<SysLogDaylightConfigurationSync> lastSync = syncLogDao
.findTopByConfigNameAndDlPropertyIdAndSyncStatusOrderByLastSyncAtDesc(
"Configuration", dlPropertyId, "SUCCESS");
boolean hasSavedConfig = cfgDaylightConfigurationDao.existsSavedConfigurationByDlPropertyId(dlPropertyId);
if (lastSync.isPresent() && hasSavedConfig) {
updatedAtParam = "&updatedAt=" + sdf.format(lastSync.get().getLastSyncAt());
log.info("Property {} incremental sync, updatedAt: {}", dlPropertyId, updatedAtParam);
} else {
if (lastSync.isPresent() && !hasSavedConfig) {
log.warn("Property {} sync log found but config data missing, fallback to full sync", dlPropertyId);
} else {
log.info("Property {} first sync, no updatedAt parameter", dlPropertyId);
}
}
// 每个 property 先删除旧配置,再重新拉取
Map<String, List<JSONObject>> accumulatedResults = new HashMap<>();
String path = "/api-gateway/aggregator/v1/configuration/extract";
String apiUrl = daylightApiSetting.getServerUrl() + path;
String types = "PurchaseElement,MarketSegment,RatePlan,BookingSource,MembershipLevel," +
"Attribute,RoomType,GuaranteeType,DistributionChannel,AgeBucket,CancellationReason," +
"ComplimentaryAccountingPreset,ComplimentaryType,TransactionCode";
String pagingNext;
int pageNumber = 1;
boolean fetchSuccess = true;
do {
HttpHeaders headers = new HttpHeaders();
headers.set("authorization", "Bearer " + daylightApiToken.getAccessToken());
headers.set("Ac-Property-Id", dlPropertyId);
String queryString = "types=" + types + "&pageSize=500&pageNumber=" + pageNumber + updatedAtParam;
log.info("Fetching page {} for Ac-Property-Id: {}", pageNumber, dlPropertyId);
ResponseEntity<byte[]> requestResponse = webProxyService.invokeRequest(
WebProxyService.DAYLIGHT_API,
HttpMethod.GET,
apiUrl,
queryString,
headers,
new byte[0],
Duration.ofSeconds(daylightApiSetting.getApiTimeout()),
httpErrorHandler
).block();
if (requestResponse == null) {
log.warn("Property {} configuration fetch failed: Http request server can not visit", dlPropertyId);
fetchSuccess = false;
break;
}
response.setStatusCode(requestResponse.getStatusCode().value());
if (!requestResponse.getStatusCode().is2xxSuccessful()) {
byte[] errorBody = requestResponse.getBody();
String errorMsg = errorBody != null ? new String(errorBody, StandardCharsets.UTF_8) : "Request failed";
log.warn("Property {} configuration fetch failed: {}", dlPropertyId, errorMsg);
fetchSuccess = false;
break;
}
byte[] responseBody = requestResponse.getBody();
if (responseBody == null) {
break;
}
String jsonStr = new String(responseBody, StandardCharsets.UTF_8);
JSONObject responseJson = JSONObject.parseObject(jsonStr);
// 累积 results 中每种 configType 的数据
JSONObject results = responseJson.getJSONObject("results");
if (results != null) {
for (String configType : results.keySet()) {
List<JSONObject> pageItems = results.getJSONArray(configType).toJavaList(JSONObject.class);
accumulatedResults.computeIfAbsent(configType, k -> new ArrayList<>()).addAll(pageItems);
}
}
// 解析 paging.next,判断是否有下一页
pagingNext = null;
JSONObject paging = responseJson.getJSONObject("paging");
if (paging != null && paging.containsKey("next") && StringUtils.isNotBlank(paging.getString("next"))) {
pagingNext = paging.getString("next");
pageNumber++;
}
} while (pagingNext != null);
// 将累积的结果保存为 CfgDaylightConfiguration
boolean isIncremental = StringUtils.isNotBlank(updatedAtParam);
for (Map.Entry<String, List<JSONObject>> entry : accumulatedResults.entrySet()) {
String configType = entry.getKey();
List<JSONObject> newItems = entry.getValue();
if (isIncremental) {
// 增量同步:合并新旧数据
CfgDaylightConfiguration existing = cfgDaylightConfigurationDao
.findByDlPropertyIdAndConfigName(dlPropertyId, configType);
if (existing != null && StringUtils.isNotBlank(existing.getConfigValue())) {
// 解析旧数据,用 id 建索引
List<JSONObject> oldItems = JSONObject.parseArray(existing.getConfigValue(), JSONObject.class);
Map<String, JSONObject> mergedMap = new HashMap<>();
for (JSONObject item : oldItems) {
mergedMap.put(getConfigItemKey(item), item);
}
logConfigurationChanges("Configuration incremental sync", dlPropertyId, configType, oldItems, newItems);
// 用新数据覆盖/新增
for (JSONObject item : newItems) {
mergedMap.put(getConfigItemKey(item), item);
}
// 保存合并后的结果
existing.setConfigValue(JSONObject.toJSONString(new ArrayList<>(mergedMap.values())));
existing.setUpdatedAt(new Date());
cfgDaylightConfigurationDao.save(existing);
log.info("Merged {} for {}: old={}, new={}, merged={}",
configType, dlPropertyId, oldItems.size(), newItems.size(), mergedMap.size());
} else {
// DB 中没有旧记录,直接保存新数据
CfgDaylightConfiguration config = new CfgDaylightConfiguration();
config.setConfigName(configType);
config.setConfigValue(JSONObject.toJSONString(newItems));
config.setDlPropertyId(dlPropertyId);
config.setCreatedAt(new Date());
config.setUpdatedAt(new Date());
cfgDaylightConfigurationDao.save(config);
logConfigurationCreated("Configuration incremental sync created", dlPropertyId, configType, newItems);
}
} else {
// 全量同步:直接保存
CfgDaylightConfiguration existing = cfgDaylightConfigurationDao
.findByDlPropertyIdAndConfigName(dlPropertyId, configType);
List<JSONObject> oldItems = existing != null && StringUtils.isNotBlank(existing.getConfigValue())
? JSONObject.parseArray(existing.getConfigValue(), JSONObject.class)
: new ArrayList<>();
CfgDaylightConfiguration config = existing != null ? existing : new CfgDaylightConfiguration();
config.setConfigName(configType);
config.setConfigValue(JSONObject.toJSONString(newItems));
config.setDlPropertyId(dlPropertyId);
if (config.getCreatedAt() == null) {
config.setCreatedAt(new Date());
}
config.setUpdatedAt(new Date());
cfgDaylightConfigurationDao.save(config);
logConfigurationChanges("Configuration full sync", dlPropertyId, configType, oldItems, newItems);
}
savedCount++;
}
// 按 property 记录同步日志
SysLogDaylightConfigurationSync syncLog = new SysLogDaylightConfigurationSync();
syncLog.setConfigName("Configuration");
syncLog.setDlPropertyId(dlPropertyId);
syncLog.setLastSyncAt(syncStartTime);
syncLog.setSyncStatus(fetchSuccess ? "SUCCESS" : "FAILED");
syncLog.setRecordCount(accumulatedResults.size());
syncLog.setCreatedAt(new Date());
syncLogDao.save(syncLog);
}
response.setSuccess(true);
response.setMessage("Successfully fetched and saved " + savedCount + " configuration entries.");
} catch (Exception e) {
response.setSuccess(false);
response.setMessage(e.getMessage());
}
return response;
}
/**
* 从 Daylight API 拉取 properties 列表,存入 cfg_daylight_configuration 表
*/
public BaseApiResponse fetchDaylightProperties() {
BaseApiResponse response = new BaseApiResponse();
Date syncStartTime = new Date();
try {
TokenResponse daylightApiToken = daylightTokenService.getApiAccessToken();
if (daylightApiToken == null || StringUtils.isBlank(daylightApiToken.getAccessToken())) {
response.setSuccess(false);
response.setMessage("Invoke daylight token failed");
return response;
}
String path = "/api-gateway/configuration/v1/properties";
String apiUrl = daylightApiSetting.getServerUrl() + path;
int pageNumber = 1;
List<JSONObject> allResults = new ArrayList<>();
String pagingNext = null;
do {
HttpHeaders headers = new HttpHeaders();
headers.set("authorization", "Bearer " + daylightApiToken.getAccessToken());
String queryString = "pageSize=500&statusCode=Published&recursive=true&isActive=true&pageNumber=" + pageNumber;
log.info("Fetching properties page {}", pageNumber);
ResponseEntity<byte[]> requestResponse = webProxyService.invokeRequest(
WebProxyService.DAYLIGHT_API,
HttpMethod.GET,
apiUrl,
queryString,
headers,
new byte[0],
Duration.ofSeconds(daylightApiSetting.getApiTimeout()),
httpErrorHandler
).block();
if (requestResponse == null) {
response.setSuccess(false);
response.setMessage("Http request server can not visit.");
return response;
}
response.setStatusCode(requestResponse.getStatusCode().value());
if (!requestResponse.getStatusCode().is2xxSuccessful()) {
byte[] errorBody = requestResponse.getBody();
response.setSuccess(false);
response.setMessage(errorBody != null ? new String(errorBody, StandardCharsets.UTF_8) : "Request failed");
return response;
}
byte[] responseBody = requestResponse.getBody();
if (responseBody == null) {
break;
}
String jsonStr = new String(responseBody, StandardCharsets.UTF_8);
JSONObject responseJson = JSONObject.parseObject(jsonStr);
// 累积 results 数组
List<JSONObject> pageResults = responseJson.getJSONArray("results").toJavaList(JSONObject.class);
if (pageResults != null) {
allResults.addAll(pageResults);
}
// 判断是否有下一页
pagingNext = null;
JSONObject paging = responseJson.getJSONObject("paging");
if (paging != null) {
int totalCount = paging.getIntValue("totalCount");
int pageSize = paging.getIntValue("pageSize");
if (pageNumber * pageSize < totalCount) {
pagingNext = "next";
pageNumber++;
}
}
} while (pagingNext != null);
// 保存为一条 CfgDaylightConfiguration,configName = "Property"
if (!allResults.isEmpty()) {
CfgDaylightConfiguration config = cfgDaylightConfigurationDao
.findByDlPropertyIdAndConfigName(null, "Property");
List<JSONObject> oldItems = config != null && StringUtils.isNotBlank(config.getConfigValue())
? JSONObject.parseArray(config.getConfigValue(), JSONObject.class)
: new ArrayList<>();
if (config == null) {
config = new CfgDaylightConfiguration();
config.setConfigName("Property");
config.setDlPropertyId(null);
config.setCreatedAt(new Date());
}
config.setConfigValue(JSONObject.toJSONString(allResults));
config.setUpdatedAt(new Date());
cfgDaylightConfigurationDao.save(config);
logConfigurationChanges("Property sync", null, "Property", oldItems, allResults);
}
response.setSuccess(true);
response.setMessage("Successfully fetched and saved " + allResults.size() + " properties.");
// 记录同步日志
SysLogDaylightConfigurationSync syncLog = new SysLogDaylightConfigurationSync();
syncLog.setConfigName("Property");
syncLog.setLastSyncAt(syncStartTime);
syncLog.setSyncStatus("SUCCESS");
syncLog.setRecordCount(allResults.size());
syncLog.setCreatedAt(new Date());
syncLogDao.save(syncLog);
} catch (Exception e) {
response.setSuccess(false);
response.setMessage(e.getMessage());
// 记录失败日志
SysLogDaylightConfigurationSync syncLog = new SysLogDaylightConfigurationSync();
syncLog.setConfigName("Property");
syncLog.setLastSyncAt(syncStartTime);
syncLog.setSyncStatus("FAILED");
syncLog.setRecordCount(0);
syncLog.setCreatedAt(new Date());
syncLogDao.save(syncLog);
}
return response;
}
private void logConfigurationChanges(String action, String dlPropertyId, String configType,
List<JSONObject> oldItems, List<JSONObject> newItems) {
Map<String, JSONObject> oldItemMap = toConfigItemMap(oldItems);
List<String> addedItems = new ArrayList<>();
List<String> updatedItems = new ArrayList<>();
List<String> removedItems = new ArrayList<>();
for (JSONObject newItem : newItems) {
String itemKey = getConfigItemKey(newItem);
JSONObject oldItem = oldItemMap.remove(itemKey);
if (oldItem == null) {
addedItems.add(formatConfigItem(newItem));
} else if (!JSONObject.toJSONString(oldItem).equals(JSONObject.toJSONString(newItem))) {
updatedItems.add(formatConfigItem(newItem));
}
}
for (JSONObject removedItem : oldItemMap.values()) {
removedItems.add(formatConfigItem(removedItem));
}
log.info("{} configName={}, dlPropertyId={}, oldCount={}, newCount={}, addedCount={}, updatedCount={}, removedCount={}, added={}, updated={}, removed={}",
action, configType, dlPropertyId, oldItems.size(), newItems.size(), addedItems.size(), updatedItems.size(),
removedItems.size(), limitLogItems(addedItems), limitLogItems(updatedItems), limitLogItems(removedItems));
}
private void logConfigurationCreated(String action, String dlPropertyId, String configType, List<JSONObject> newItems) {
log.info("{} configName={}, dlPropertyId={}, newCount={}, items={}",
action, configType, dlPropertyId, newItems.size(), limitLogItems(formatConfigItems(newItems)));
}
private Map<String, JSONObject> toConfigItemMap(List<JSONObject> items) {
Map<String, JSONObject> itemMap = new HashMap<>();
for (int i = 0; i < items.size(); i++) {
JSONObject item = items.get(i);
itemMap.put(getConfigItemKey(item, i), item);
}
return itemMap;
}
private List<String> formatConfigItems(List<JSONObject> items) {
List<String> formattedItems = new ArrayList<>();
for (JSONObject item : items) {
formattedItems.add(formatConfigItem(item));
}
return formattedItems;
}
private String getConfigItemKey(JSONObject item) {
return getConfigItemKey(item, -1);
}
private String getConfigItemKey(JSONObject item, int index) {
String itemKey = firstNotBlank(item, "id", "code", "propertyId", "propertyCode", "name");
if (StringUtils.isNotBlank(itemKey)) {
return itemKey;
}
return index >= 0 ? "index:" + index : JSONObject.toJSONString(item);
}
private String formatConfigItem(JSONObject item) {
List<String> parts = new ArrayList<>();
addIfNotBlank(parts, "id", item.getString("id"));
addIfNotBlank(parts, "code", firstNotBlank(item, "code", "propertyCode"));
addIfNotBlank(parts, "name", firstNotBlank(item, "name", "displayName", "shortName"));
if (parts.isEmpty()) {
return JSONObject.toJSONString(item);
}
return StringUtils.join(parts, ",");
}
private String firstNotBlank(JSONObject item, String... fieldNames) {
for (String fieldName : fieldNames) {
String value = item.getString(fieldName);
if (StringUtils.isNotBlank(value)) {
return value;
}
}
return null;
}
private void addIfNotBlank(List<String> parts, String name, String value) {
if (StringUtils.isNotBlank(value)) {
parts.add(name + "=" + value);
}
}
private List<String> limitLogItems(List<String> items) {
int maxLogItemCount = 50;
if (items.size() <= maxLogItemCount) {
return items;
}
List<String> limitedItems = new ArrayList<>(items.subList(0, maxLogItemCount));
limitedItems.add("... total " + items.size() + " items");
return limitedItems;
}
/**
* 从 Daylight API 拉取 block codes 列表,按 property 遍历,存入 cfg_daylight_configuration 表
*/
public BaseApiResponse fetchDaylightBlockCodes() {
BaseApiResponse response = new BaseApiResponse();
Date syncStartTime = new Date();
String dlPropertyId = null;
try {
TokenResponse daylightApiToken = daylightTokenService.getApiAccessToken();
if (daylightApiToken == null || StringUtils.isBlank(daylightApiToken.getAccessToken())) {
response.setSuccess(false);
response.setMessage("Invoke daylight token failed");
return response;
}
List<CfgProperties> allProperties = propertyDao.findByCategory("DAYLIGHT");
int savedCount = 0;
if (allProperties == null || allProperties.isEmpty()) {
response.setSuccess(false);
response.setMessage("No properties found with category 'DAYLIGHT'");
return response;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
for (CfgProperties property : allProperties) {
dlPropertyId = property.getDlPropertyId();
if (StringUtils.isBlank(dlPropertyId)) {
continue;
}
// 查上次成功同步时间,决定是否走增量
String updatedAtParam = "";
Optional<SysLogDaylightConfigurationSync> lastSync = syncLogDao
.findTopByConfigNameAndDlPropertyIdAndSyncStatusOrderByLastSyncAtDesc(
"BlockCode", dlPropertyId, "SUCCESS");
CfgDaylightConfiguration existingConfig = cfgDaylightConfigurationDao
.findByDlPropertyIdAndConfigName(dlPropertyId, "BlockCode");
if (lastSync.isPresent() && existingConfig != null) {
updatedAtParam = "&updatedAt=" + sdf.format(lastSync.get().getLastSyncAt());
log.info("Property {} BlockCode incremental sync, updatedAt: {}", dlPropertyId, updatedAtParam);
} else {
if (lastSync.isPresent() && existingConfig == null) {
log.warn("Property {} BlockCode sync log found but config data missing, fallback to full sync", dlPropertyId);
} else {
log.info("Property {} BlockCode first sync, no updatedAt parameter", dlPropertyId);
}
}
String path = "/api-gateway/data-api/v1/blocks";
String apiUrl = daylightApiSetting.getServerUrl() + path;
List<JSONObject> allResults = new ArrayList<>();
HttpHeaders headers = new HttpHeaders();
headers.set("authorization", "Bearer " + daylightApiToken.getAccessToken());
headers.set("Ac-Property-Id", dlPropertyId);
String queryString = "pageSize=200" + updatedAtParam;
log.info("Fetching block codes for Ac-Property-Id: {}", dlPropertyId);
ResponseEntity<byte[]> requestResponse = webProxyService.invokeRequest(
WebProxyService.DAYLIGHT_API,
HttpMethod.GET,
apiUrl,
queryString,
headers,
new byte[0],
Duration.ofSeconds(daylightApiSetting.getApiTimeout()),
httpErrorHandler
).block();
if (requestResponse == null) {
response.setSuccess(false);
response.setMessage("Http request server can not visit.");
return response;
}
response.setStatusCode(requestResponse.getStatusCode().value());
if (!requestResponse.getStatusCode().is2xxSuccessful()) {
byte[] errorBody = requestResponse.getBody();
response.setSuccess(false);
response.setMessage(errorBody != null ? new String(errorBody, StandardCharsets.UTF_8) : "Request failed");
return response;
}
byte[] responseBody = requestResponse.getBody();
if (responseBody != null) {
String jsonStr = new String(responseBody, StandardCharsets.UTF_8);
JSONObject responseJson = JSONObject.parseObject(jsonStr);
List<JSONObject> pageResults = responseJson.getJSONArray("results").toJavaList(JSONObject.class);
if (pageResults != null) {
allResults.addAll(pageResults);
}
}
// 保存为一条 CfgDaylightConfiguration,configName = "BlockCode"
if (!allResults.isEmpty()) {
boolean isIncremental = StringUtils.isNotBlank(updatedAtParam);
if (isIncremental && existingConfig != null
&& StringUtils.isNotBlank(existingConfig.getConfigValue())) {
// 增量同步:按 id 合并新旧数据
List<JSONObject> oldItems = JSONObject.parseArray(existingConfig.getConfigValue(), JSONObject.class);
Map<String, JSONObject> mergedMap = new HashMap<>();
for (JSONObject item : oldItems) {
mergedMap.put(getConfigItemKey(item), item);
}
logConfigurationChanges("BlockCode incremental sync", dlPropertyId, "BlockCode", oldItems, allResults);
for (JSONObject item : allResults) {
mergedMap.put(getConfigItemKey(item), item);
}
existingConfig.setConfigValue(JSONObject.toJSONString(new ArrayList<>(mergedMap.values())));
existingConfig.setUpdatedAt(new Date());
cfgDaylightConfigurationDao.save(existingConfig);
log.info("Merged BlockCode for {}: old={}, new={}, merged={}",
dlPropertyId, oldItems.size(), allResults.size(), mergedMap.size());
} else {
// 全量同步:直接保存
List<JSONObject> oldItems = existingConfig != null
&& StringUtils.isNotBlank(existingConfig.getConfigValue())
? JSONObject.parseArray(existingConfig.getConfigValue(), JSONObject.class)
: new ArrayList<>();
CfgDaylightConfiguration config = existingConfig != null ? existingConfig : new CfgDaylightConfiguration();
if (config.getConfigName() == null) {
config.setConfigName("BlockCode");
config.setDlPropertyId(dlPropertyId);
}
if (config.getCreatedAt() == null) {
config.setCreatedAt(new Date());
}
config.setConfigValue(JSONObject.toJSONString(allResults));
config.setUpdatedAt(new Date());
cfgDaylightConfigurationDao.save(config);
logConfigurationChanges("BlockCode full sync", dlPropertyId, "BlockCode", oldItems, allResults);
}
savedCount++;
}
}
response.setSuccess(true);
response.setMessage("Successfully fetched and saved " + savedCount + " block code entries.");
// 记录同步日志
SysLogDaylightConfigurationSync syncLog = new SysLogDaylightConfigurationSync();
syncLog.setConfigName("BlockCode");
syncLog.setLastSyncAt(syncStartTime);
syncLog.setSyncStatus("SUCCESS");
syncLog.setDlPropertyId(dlPropertyId);
syncLog.setRecordCount(savedCount);
syncLog.setCreatedAt(new Date());
syncLogDao.save(syncLog);
} catch (Exception e) {
response.setSuccess(false);
response.setMessage(e.getMessage());
// 记录失败日志
SysLogDaylightConfigurationSync syncLog = new SysLogDaylightConfigurationSync();
syncLog.setConfigName("BlockCode");
syncLog.setDlPropertyId(dlPropertyId);
syncLog.setLastSyncAt(syncStartTime);
syncLog.setSyncStatus("FAILED");
syncLog.setRecordCount(0);
syncLog.setCreatedAt(new Date());
syncLogDao.save(syncLog);
}
return response;
}
}

Some files were not shown because too many files have changed in this diff Show More