summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--galaxy-business-api/pom.xml11
-rw-r--r--galaxy-business-api/src/main/java/com/mesalab/api/common/base/SchemaBase.java2
-rw-r--r--galaxy-business-api/src/main/java/com/mesalab/api/modules/network/TreeUtils.java2
-rw-r--r--galaxy-business-api/src/main/java/com/mesalab/api/modules/network/dsl/DSLValidate.java2
-rw-r--r--galaxy-business-api/src/main/java/com/mesalab/api/modules/network/service/impl/NetworkMonitorServiceImpl.java4
-rw-r--r--galaxy-hos-service/pom.xml2
-rw-r--r--galaxy-job-executor/pom.xml11
-rw-r--r--galaxy-job-executor/src/main/java/com/mesalab/job/executor/core/utils/HttpClientUtils.java2
-rw-r--r--galaxy-job-executor/src/main/java/com/mesalab/job/executor/core/utils/KafkaUtils.java4
-rw-r--r--galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/DataflowJob.java4
-rw-r--r--galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/DruidNativeQueryJob.java4
-rw-r--r--galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/LogStorageQuotaJob.java2
-rw-r--r--galaxy-job-executor/src/main/java/com/mesalab/job/executor/service/StorageQuotaService.java6
-rw-r--r--galaxy-query-engine/pom.xml11
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/calcite/CalciteMemoryUtils.java4
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/calcite/function/DateFunction.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/base/SchemaBase.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ClickHouseConfiguration.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/ConvertUtil.java4
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/IPUtil.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/QueryCacheUtils.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/ReportCacheUtils.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/SQLFunctionUtil.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/TableFinder.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/TreeUtils.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/JwtCache.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/controller/KnowledgeController.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Match.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/service/KnowledgeService.java6
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/BaseQueryProvider.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/FqdnProviderImpl.java4
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/IpProviderImpl.java4
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/SubscriberIdProviderImpl.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/ApiController.java4
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/AuditLogAspect.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/MetadataController.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/SystemController.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractDataSourceDialect.java4
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractEngineDialect.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/ClickHouseDialect.java4
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/DruidDialect.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/FederationDialect.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/interceptor/QuerySubmitInterceptor.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ApiParam.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/SQLQuerySource.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_CITY.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_COUNTRY.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_GEO.java6
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/TIME_FLOOR_WITH_FILL.java4
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/protocol/ProtocolTree.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/ArangoHealthIndicator.java4
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/ApiServiceImpl.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/HttpClientService.java2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/MetadataServiceImpl.java4
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/SystemServiceImpl.java10
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/TestSqlServiceImpl.java12
-rw-r--r--galaxy-tool/pom.xml74
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/crypt/AESUtil.java156
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/crypt/BCrypt.java775
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/crypt/CertificateCoder.java214
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/crypt/Cryptos.java257
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/crypt/DesFileUtil.java124
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/crypt/DesUtil.java157
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/crypt/Digests.java124
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/crypt/RSACoder.java313
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/crypt/package.html58
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/domain/JsonInjector.java44
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/domain/LocationResponse.java142
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/domain/Nets.java31
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/exception/Exceptions.java57
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/file/FileApplication.java631
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/file/FileFilterExtension.java84
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/AbstractIpLookup.java102
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/AsnLookup.java473
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/CIDRUtils.java138
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/CommonUtil.java246
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/CookieUtil.java190
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/DateUtil.java470
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/DateUtils.java822
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/Encodes.java145
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/FormatUtils.java236
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/GalaxyDataBaseReader.java197
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/IPUtil.java766
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/IpLookup.java682
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/JsonMapper.java248
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/MathUtils.java290
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/SnowflakeId.java234
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/StringUtil.java729
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/TimeConstants.java40
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/ZooKeeperLock.java140
-rw-r--r--galaxy-tool/src/main/java/com/mesalab/tool/utils/ZookeeperUtils.java139
-rw-r--r--pom.xml33
92 files changed, 9625 insertions, 133 deletions
diff --git a/galaxy-business-api/pom.xml b/galaxy-business-api/pom.xml
index 1bc0040..0798c85 100644
--- a/galaxy-business-api/pom.xml
+++ b/galaxy-business-api/pom.xml
@@ -63,14 +63,9 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>com.zdjizhi</groupId>
- <artifactId>galaxy</artifactId>
- <exclusions>
- <exclusion>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- </exclusion>
- </exclusions>
+ <groupId>com.mesalab</groupId>
+ <artifactId>galaxy-tool</artifactId>
+ <version>${project.parent.version}</version>
</dependency>
</dependencies>
diff --git a/galaxy-business-api/src/main/java/com/mesalab/api/common/base/SchemaBase.java b/galaxy-business-api/src/main/java/com/mesalab/api/common/base/SchemaBase.java
index dfae837..5d09e10 100644
--- a/galaxy-business-api/src/main/java/com/mesalab/api/common/base/SchemaBase.java
+++ b/galaxy-business-api/src/main/java/com/mesalab/api/common/base/SchemaBase.java
@@ -22,7 +22,7 @@ public class SchemaBase implements Serializable {
private List<Map> fields;
public String getNamespace() {
- return namespace = "com.zdjizhi";
+ return namespace = "com.mesalab.tool";
}
public String getType() {
diff --git a/galaxy-business-api/src/main/java/com/mesalab/api/modules/network/TreeUtils.java b/galaxy-business-api/src/main/java/com/mesalab/api/modules/network/TreeUtils.java
index 37aaaab..045173f 100644
--- a/galaxy-business-api/src/main/java/com/mesalab/api/modules/network/TreeUtils.java
+++ b/galaxy-business-api/src/main/java/com/mesalab/api/modules/network/TreeUtils.java
@@ -1,7 +1,7 @@
package com.mesalab.api.modules.network;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
diff --git a/galaxy-business-api/src/main/java/com/mesalab/api/modules/network/dsl/DSLValidate.java b/galaxy-business-api/src/main/java/com/mesalab/api/modules/network/dsl/DSLValidate.java
index af11539..ac729cd 100644
--- a/galaxy-business-api/src/main/java/com/mesalab/api/modules/network/dsl/DSLValidate.java
+++ b/galaxy-business-api/src/main/java/com/mesalab/api/modules/network/dsl/DSLValidate.java
@@ -3,7 +3,7 @@ package com.mesalab.api.modules.network.dsl;
import com.mesalab.api.common.enums.ResultCodeEnum;
import com.mesalab.api.common.exception.BusinessException;
import com.mesalab.api.modules.network.MatchEnum;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang3.EnumUtils;
import org.apache.http.HttpStatus;
diff --git a/galaxy-business-api/src/main/java/com/mesalab/api/modules/network/service/impl/NetworkMonitorServiceImpl.java b/galaxy-business-api/src/main/java/com/mesalab/api/modules/network/service/impl/NetworkMonitorServiceImpl.java
index 66ad39d..6b15e09 100644
--- a/galaxy-business-api/src/main/java/com/mesalab/api/modules/network/service/impl/NetworkMonitorServiceImpl.java
+++ b/galaxy-business-api/src/main/java/com/mesalab/api/modules/network/service/impl/NetworkMonitorServiceImpl.java
@@ -13,8 +13,8 @@ import com.mesalab.api.modules.network.dsl.DSLObject;
import com.mesalab.api.modules.network.protocol.ProtocolTree;
import com.mesalab.api.modules.network.service.NetworkMonitorService;
import com.mesalab.api.common.enums.*;
-import com.zdjizhi.utils.JsonMapper;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.JsonMapper;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
diff --git a/galaxy-hos-service/pom.xml b/galaxy-hos-service/pom.xml
index 6361f4d..3cd6c88 100644
--- a/galaxy-hos-service/pom.xml
+++ b/galaxy-hos-service/pom.xml
@@ -92,7 +92,7 @@
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
- <version>1.11.700</version>
+ <version>${aws-java-sdk.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
diff --git a/galaxy-job-executor/pom.xml b/galaxy-job-executor/pom.xml
index 871e7ac..1e99ae7 100644
--- a/galaxy-job-executor/pom.xml
+++ b/galaxy-job-executor/pom.xml
@@ -54,14 +54,9 @@
<version>${project.parent.version}</version>
</dependency>
<dependency>
- <groupId>com.zdjizhi</groupId>
- <artifactId>galaxy</artifactId>
- <exclusions>
- <exclusion>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- </exclusion>
- </exclusions>
+ <groupId>com.mesalab</groupId>
+ <artifactId>galaxy-tool</artifactId>
+ <version>${project.parent.version}</version>
</dependency>
</dependencies>
diff --git a/galaxy-job-executor/src/main/java/com/mesalab/job/executor/core/utils/HttpClientUtils.java b/galaxy-job-executor/src/main/java/com/mesalab/job/executor/core/utils/HttpClientUtils.java
index 1c74605..610ab71 100644
--- a/galaxy-job-executor/src/main/java/com/mesalab/job/executor/core/utils/HttpClientUtils.java
+++ b/galaxy-job-executor/src/main/java/com/mesalab/job/executor/core/utils/HttpClientUtils.java
@@ -2,7 +2,7 @@ package com.mesalab.job.executor.core.utils;
import com.mesalab.job.executor.core.config.HttpConfig;
import com.mesalab.job.executor.exception.BusinessException;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import org.apache.commons.io.IOUtils;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
diff --git a/galaxy-job-executor/src/main/java/com/mesalab/job/executor/core/utils/KafkaUtils.java b/galaxy-job-executor/src/main/java/com/mesalab/job/executor/core/utils/KafkaUtils.java
index c92b8c3..4aeda2c 100644
--- a/galaxy-job-executor/src/main/java/com/mesalab/job/executor/core/utils/KafkaUtils.java
+++ b/galaxy-job-executor/src/main/java/com/mesalab/job/executor/core/utils/KafkaUtils.java
@@ -1,7 +1,7 @@
package com.mesalab.job.executor.core.utils;
-import com.zdjizhi.utils.JsonMapper;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.JsonMapper;
+import com.mesalab.tool.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.core.KafkaTemplate;
diff --git a/galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/DataflowJob.java b/galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/DataflowJob.java
index c3f75fb..fc080db 100644
--- a/galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/DataflowJob.java
+++ b/galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/DataflowJob.java
@@ -15,8 +15,8 @@ import com.mesalab.job.core.handler.annotation.XxlJob;
import com.mesalab.job.core.log.XxlJobLogger;
import com.mesalab.job.executor.core.utils.HttpClientUtils;
import com.mesalab.job.executor.core.utils.KafkaUtils;
-import com.zdjizhi.utils.JsonMapper;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.JsonMapper;
+import com.mesalab.tool.utils.StringUtil;
import io.netty.handler.codec.http.HttpMethod;
diff --git a/galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/DruidNativeQueryJob.java b/galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/DruidNativeQueryJob.java
index cf982e3..27724ba 100644
--- a/galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/DruidNativeQueryJob.java
+++ b/galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/DruidNativeQueryJob.java
@@ -10,8 +10,8 @@ import com.mesalab.job.core.handler.annotation.XxlJob;
import com.mesalab.job.core.log.XxlJobLogger;
import com.mesalab.job.executor.core.utils.HttpClientUtils;
import com.mesalab.job.executor.core.utils.KafkaUtils;
-import com.zdjizhi.utils.JsonMapper;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.JsonMapper;
+import com.mesalab.tool.utils.StringUtil;
import io.netty.handler.codec.http.HttpMethod;
import org.joda.time.DateTimeZone;
import org.joda.time.Interval;
diff --git a/galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/LogStorageQuotaJob.java b/galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/LogStorageQuotaJob.java
index 6ed7233..cb2ddf7 100644
--- a/galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/LogStorageQuotaJob.java
+++ b/galaxy-job-executor/src/main/java/com/mesalab/job/executor/jobhandler/LogStorageQuotaJob.java
@@ -14,7 +14,7 @@ import com.mesalab.job.core.biz.model.ReturnT;
import com.mesalab.job.core.handler.IJobHandler;
import com.mesalab.job.core.handler.annotation.XxlJob;
import com.mesalab.job.core.log.XxlJobLogger;
-import com.zdjizhi.utils.*;
+import com.mesalab.tool.utils.*;
import org.apache.http.Header;
import org.apache.http.message.BasicHeader;
import org.slf4j.Logger;
diff --git a/galaxy-job-executor/src/main/java/com/mesalab/job/executor/service/StorageQuotaService.java b/galaxy-job-executor/src/main/java/com/mesalab/job/executor/service/StorageQuotaService.java
index 3a731a3..edab813 100644
--- a/galaxy-job-executor/src/main/java/com/mesalab/job/executor/service/StorageQuotaService.java
+++ b/galaxy-job-executor/src/main/java/com/mesalab/job/executor/service/StorageQuotaService.java
@@ -11,9 +11,9 @@ import com.mesalab.job.executor.core.utils.JobUtil;
import com.mesalab.job.executor.core.utils.ZookeeperUtils;
import com.mesalab.job.executor.exception.BusinessException;
import com.mesalab.job.core.log.XxlJobLogger;
-import com.zdjizhi.utils.DateUtils;
-import com.zdjizhi.utils.JsonMapper;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.DateUtils;
+import com.mesalab.tool.utils.JsonMapper;
+import com.mesalab.tool.utils.StringUtil;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/galaxy-query-engine/pom.xml b/galaxy-query-engine/pom.xml
index 835beef..06686c2 100644
--- a/galaxy-query-engine/pom.xml
+++ b/galaxy-query-engine/pom.xml
@@ -48,14 +48,9 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>com.zdjizhi</groupId>
- <artifactId>galaxy</artifactId>
- <exclusions>
- <exclusion>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- </exclusion>
- </exclusions>
+ <groupId>com.mesalab</groupId>
+ <artifactId>galaxy-tool</artifactId>
+ <version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/calcite/CalciteMemoryUtils.java b/galaxy-query-engine/src/main/java/com/mesalab/calcite/CalciteMemoryUtils.java
index c84cdb7..50fa6ad 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/calcite/CalciteMemoryUtils.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/calcite/CalciteMemoryUtils.java
@@ -8,7 +8,7 @@ import com.google.common.collect.Maps;
import com.mesalab.calcite.storage.DataTypeMapping;
import com.mesalab.calcite.storage.Storage;
import com.mesalab.common.exception.BusinessException;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.calcite.jdbc.CalciteConnection;
import org.apache.commons.lang3.StringUtils;
@@ -18,7 +18,7 @@ import java.sql.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
-import static com.zdjizhi.utils.StringUtil.setDefaultIfEmpty;
+import static com.mesalab.tool.utils.StringUtil.setDefaultIfEmpty;
import static org.apache.commons.lang3.StringUtils.defaultIfEmpty;
@Slf4j
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/calcite/function/DateFunction.java b/galaxy-query-engine/src/main/java/com/mesalab/calcite/function/DateFunction.java
index 1801c9c..221c4f4 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/calcite/function/DateFunction.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/calcite/function/DateFunction.java
@@ -1,6 +1,6 @@
package com.mesalab.calcite.function;
-import com.zdjizhi.utils.DateUtils;
+import com.mesalab.tool.utils.DateUtils;
public class DateFunction {
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/base/SchemaBase.java b/galaxy-query-engine/src/main/java/com/mesalab/common/base/SchemaBase.java
index aff97f9..f85cdf3 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/common/base/SchemaBase.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/base/SchemaBase.java
@@ -22,7 +22,7 @@ public class SchemaBase implements Serializable {
private List<Map> fields;
public String getNamespace() {
- return namespace = "com.zdjizhi";
+ return namespace = "com.mesalab.tool";
}
public String getType() {
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ClickHouseConfiguration.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ClickHouseConfiguration.java
index fe684af..8f3dd25 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ClickHouseConfiguration.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ClickHouseConfiguration.java
@@ -1,7 +1,7 @@
package com.mesalab.common.configuration;
import com.mesalab.qgw.model.api.ClickHouseHttpSource;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ConvertUtil.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ConvertUtil.java
index 43736f0..0e62895 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ConvertUtil.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ConvertUtil.java
@@ -3,8 +3,8 @@ package com.mesalab.common.utils;
import com.google.common.base.Joiner;
import com.google.common.collect.*;
import com.mesalab.common.support.IConvertor;
-import com.zdjizhi.utils.DateUtils;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.DateUtils;
+import com.mesalab.tool.utils.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.nutz.lang.Lang;
import java.util.*;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/IPUtil.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/IPUtil.java
index 5a26fb1..836700d 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/IPUtil.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/IPUtil.java
@@ -1,6 +1,6 @@
package com.mesalab.common.utils;
-import com.zdjizhi.utils.IpLookup;
+import com.mesalab.tool.utils.IpLookup;
import javax.servlet.http.HttpServletRequest;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/QueryCacheUtils.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/QueryCacheUtils.java
index 07ee3d7..96d40ea 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/QueryCacheUtils.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/QueryCacheUtils.java
@@ -3,7 +3,7 @@ package com.mesalab.common.utils;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheStats;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ReportCacheUtils.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ReportCacheUtils.java
index c31c1ec..38fd291 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ReportCacheUtils.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ReportCacheUtils.java
@@ -7,7 +7,7 @@ import com.mesalab.common.enums.ResultCodeEnum;
import com.mesalab.common.enums.ResultStatusEnum;
import com.mesalab.common.exception.BusinessException;
import com.mesalab.qgw.model.api.HBaseAPISource;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.hadoop.hbase.TableName;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SQLFunctionUtil.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SQLFunctionUtil.java
index 6feb2a3..8f684d7 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SQLFunctionUtil.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SQLFunctionUtil.java
@@ -7,7 +7,7 @@ import com.mesalab.knowledge.common.utils.HttpConfig;
import com.mesalab.qgw.model.api.ClickHouseHttpSource;
import com.mesalab.qgw.model.api.DruidIoHttpSource;
import com.mesalab.qgw.service.impl.HttpClientService;
-import com.zdjizhi.utils.Encodes;
+import com.mesalab.tool.utils.Encodes;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import org.apache.http.NameValuePair;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TableFinder.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TableFinder.java
index 4ca55b7..3cf6dbf 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TableFinder.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TableFinder.java
@@ -2,7 +2,7 @@ package com.mesalab.common.utils;
import com.mesalab.common.utils.SpringContextUtil;
import com.mesalab.qgw.service.MetadataService;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import net.sf.jsqlparser.expression.*;
import net.sf.jsqlparser.expression.operators.arithmetic.*;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TreeUtils.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TreeUtils.java
index e09fbe5..8d6b7ca 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TreeUtils.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TreeUtils.java
@@ -1,7 +1,7 @@
package com.mesalab.common.utils;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/JwtCache.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/JwtCache.java
index b09825d..ff1c263 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/JwtCache.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/JwtCache.java
@@ -6,7 +6,7 @@ import java.util.concurrent.TimeUnit;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheStats;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
/**
* @description: for jwt cache
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/controller/KnowledgeController.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/controller/KnowledgeController.java
index d2fbcbf..f3fef3d 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/controller/KnowledgeController.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/controller/KnowledgeController.java
@@ -6,7 +6,7 @@ import com.mesalab.common.enums.ResultStatusEnum;
import com.mesalab.common.exception.BusinessException;
import com.mesalab.knowledge.enums.QueryTypeEnum;
import com.mesalab.knowledge.service.KnowledgeService;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.EnumUtils;
import org.springframework.beans.factory.annotation.Autowired;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Match.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Match.java
index 3e44af1..7ad2818 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Match.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Match.java
@@ -2,7 +2,7 @@ package com.mesalab.knowledge.entity;
import com.google.common.base.CharMatcher;
import com.mesalab.knowledge.enums.MatchEnum;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.Data;
import org.apache.commons.lang3.EnumUtils;
import org.springframework.util.ObjectUtils;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/service/KnowledgeService.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/service/KnowledgeService.java
index 20e7780..6b42113 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/service/KnowledgeService.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/service/KnowledgeService.java
@@ -15,9 +15,9 @@ import com.mesalab.knowledge.enums.DataSourceEnum;
import com.mesalab.knowledge.enums.MatchEnum;
import com.mesalab.knowledge.enums.RangeEnum;
import com.mesalab.knowledge.strategy.QueryProvider;
-import com.zdjizhi.utils.DateUtils;
-import com.zdjizhi.utils.JsonMapper;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.DateUtils;
+import com.mesalab.tool.utils.JsonMapper;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.Validate;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/BaseQueryProvider.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/BaseQueryProvider.java
index 599910d..366eaf0 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/BaseQueryProvider.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/BaseQueryProvider.java
@@ -6,7 +6,7 @@ import com.mesalab.knowledge.common.config.ArangoConfig;
import com.mesalab.knowledge.common.utils.Constant;
import com.mesalab.knowledge.common.utils.JwtCache;
import com.mesalab.qgw.service.impl.HttpClientService;
-import com.zdjizhi.utils.JsonMapper;
+import com.mesalab.tool.utils.JsonMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.message.BasicHeader;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/FqdnProviderImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/FqdnProviderImpl.java
index 90ead32..2cdc0cc 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/FqdnProviderImpl.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/FqdnProviderImpl.java
@@ -13,8 +13,8 @@ import com.mesalab.knowledge.entity.Parameters;
import com.mesalab.knowledge.entity.Range;
import com.mesalab.knowledge.entity.arango.IpLearningPath;
import com.mesalab.knowledge.enums.RangeEnum;
-import com.zdjizhi.utils.DateUtils;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.DateUtils;
+import com.mesalab.tool.utils.StringUtil;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.Validate;
import org.springframework.beans.factory.annotation.Autowired;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/IpProviderImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/IpProviderImpl.java
index 765ff56..e0c7d68 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/IpProviderImpl.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/IpProviderImpl.java
@@ -6,8 +6,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.mesalab.knowledge.entity.DSLObject;
import com.mesalab.knowledge.entity.Parameters;
import com.mesalab.knowledge.entity.Sort;
-import com.zdjizhi.utils.DateUtils;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.DateUtils;
+import com.mesalab.tool.utils.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/SubscriberIdProviderImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/SubscriberIdProviderImpl.java
index 6370a2b..71f2490 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/SubscriberIdProviderImpl.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/SubscriberIdProviderImpl.java
@@ -8,7 +8,7 @@ import com.google.common.collect.Maps;
import com.mesalab.knowledge.entity.DSLObject;
import com.mesalab.knowledge.entity.Match;
import com.mesalab.knowledge.entity.Parameters;
-import com.zdjizhi.utils.DateUtils;
+import com.mesalab.tool.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/ApiController.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/ApiController.java
index 0c9542b..62b3053 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/ApiController.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/ApiController.java
@@ -6,8 +6,8 @@ import com.mesalab.qgw.model.api.ApiParam;
import com.mesalab.qgw.model.api.AuditLog;
import com.mesalab.qgw.model.api.CachedSubmitCheck;
import com.mesalab.qgw.service.ApiService;
-import com.zdjizhi.utils.JsonMapper;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.JsonMapper;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/AuditLogAspect.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/AuditLogAspect.java
index 690e66a..9eb6b96 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/AuditLogAspect.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/AuditLogAspect.java
@@ -7,7 +7,7 @@ import com.mesalab.common.utils.JsonMapper;
import com.mesalab.qgw.model.api.ApiParam;
import com.mesalab.qgw.model.api.AuditLog;
import com.mesalab.qgw.model.api.AuditServiceLog;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/MetadataController.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/MetadataController.java
index bc2db36..f53406a 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/MetadataController.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/MetadataController.java
@@ -3,7 +3,7 @@ package com.mesalab.qgw.controller;
import com.mesalab.common.base.BaseResult;
import com.mesalab.common.base.BaseResultGenerator;
import com.mesalab.qgw.service.MetadataService;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/SystemController.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/SystemController.java
index 9a2e755..0aa156d 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/SystemController.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/SystemController.java
@@ -6,7 +6,7 @@ import com.mesalab.common.enums.ResultStatusEnum;
import com.mesalab.common.exception.BusinessException;
import com.mesalab.qgw.model.job.StorageDeletionInfo;
import com.mesalab.qgw.service.SystemService;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractDataSourceDialect.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractDataSourceDialect.java
index aac3bd2..bfdad28 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractDataSourceDialect.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractDataSourceDialect.java
@@ -4,8 +4,8 @@ package com.mesalab.qgw.dialect;
import com.mesalab.common.base.BaseResult;
import com.mesalab.common.base.BaseResultGenerator;
import com.mesalab.qgw.model.api.ApiParam;
-import com.zdjizhi.utils.Encodes;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.Encodes;
+import com.mesalab.tool.utils.StringUtil;
import lombok.Data;
import org.apache.calcite.rel.core.TableScan;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractEngineDialect.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractEngineDialect.java
index eb39720..88d1096 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractEngineDialect.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractEngineDialect.java
@@ -2,7 +2,7 @@ package com.mesalab.qgw.dialect;
import com.mesalab.common.base.BaseResult;
import com.mesalab.qgw.model.api.ApiParam;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.Data;
import java.util.Optional;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/ClickHouseDialect.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/ClickHouseDialect.java
index 419b1ac..9153bd2 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/ClickHouseDialect.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/ClickHouseDialect.java
@@ -12,8 +12,8 @@ import com.mesalab.qgw.model.api.*;
import com.mesalab.qgw.service.MetadataService;
import com.mesalab.qgw.service.impl.HttpClientService;
import com.mesalab.common.utils.TableFinder;
-import com.zdjizhi.utils.Encodes;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.Encodes;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/DruidDialect.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/DruidDialect.java
index a33f12d..6cd4a84 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/DruidDialect.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/DruidDialect.java
@@ -20,7 +20,7 @@ import com.mesalab.qgw.model.api.DruidIoHttpSource;
import com.mesalab.qgw.model.api.EngineConfigSource;
import com.mesalab.qgw.model.api.SQLQuerySource;
import com.mesalab.qgw.service.impl.HttpClientService;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/FederationDialect.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/FederationDialect.java
index fe3649f..99e6798 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/FederationDialect.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/FederationDialect.java
@@ -14,7 +14,7 @@ import com.mesalab.common.utils.JsonMapper;
import com.mesalab.qgw.model.api.ApiParam;
import com.mesalab.qgw.model.api.SQLQuerySource;
import com.mesalab.qgw.model.api.udf.UDF;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/interceptor/QuerySubmitInterceptor.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/interceptor/QuerySubmitInterceptor.java
index 9e5582f..1f4e8ff 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/interceptor/QuerySubmitInterceptor.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/interceptor/QuerySubmitInterceptor.java
@@ -4,7 +4,7 @@ import com.google.common.cache.CacheStats;
import com.mesalab.common.utils.QueryCacheUtils;
import com.mesalab.common.utils.JsonMapper;
import com.mesalab.qgw.model.api.CachedSubmitCheck;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ApiParam.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ApiParam.java
index 14c6341..0280e0a 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ApiParam.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ApiParam.java
@@ -1,6 +1,6 @@
package com.mesalab.qgw.model.api;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/SQLQuerySource.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/SQLQuerySource.java
index 3ea2dd9..4d78c07 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/SQLQuerySource.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/SQLQuerySource.java
@@ -5,7 +5,7 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.mesalab.qgw.model.api.udf.UDF;
import com.mesalab.qgw.service.impl.ApiServiceImpl;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.Data;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.statement.select.*;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_CITY.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_CITY.java
index 99b07f7..f87c3ac 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_CITY.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_CITY.java
@@ -3,7 +3,7 @@ package com.mesalab.qgw.model.api.udf;
import com.google.common.collect.Lists;
import com.mesalab.common.utils.IPUtil;
import com.mesalab.qgw.model.api.SQLQuerySource;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_COUNTRY.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_COUNTRY.java
index d57f5ee..8133cc2 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_COUNTRY.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_COUNTRY.java
@@ -3,7 +3,7 @@ package com.mesalab.qgw.model.api.udf;
import com.google.common.collect.Lists;
import com.mesalab.common.utils.IPUtil;
import com.mesalab.qgw.model.api.SQLQuerySource;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_GEO.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_GEO.java
index bc49146..14e5f12 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_GEO.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_GEO.java
@@ -3,9 +3,9 @@ package com.mesalab.qgw.model.api.udf;
import com.google.common.collect.Lists;
import com.mesalab.common.utils.IPUtil;
import com.mesalab.qgw.model.api.SQLQuerySource;
-import com.zdjizhi.utils.IpLookup;
-import com.zdjizhi.utils.JsonMapper;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.IpLookup;
+import com.mesalab.tool.utils.JsonMapper;
+import com.mesalab.tool.utils.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/TIME_FLOOR_WITH_FILL.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/TIME_FLOOR_WITH_FILL.java
index bf2e2d6..c20caed 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/TIME_FLOOR_WITH_FILL.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/TIME_FLOOR_WITH_FILL.java
@@ -13,8 +13,8 @@ import com.mesalab.common.utils.SpringContextUtil;
import com.mesalab.qgw.model.api.EngineConfigSource;
import com.mesalab.qgw.model.api.SQLQuerySource;
import com.mesalab.qgw.service.MetadataService;
-import com.zdjizhi.utils.DateUtils;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.DateUtils;
+import com.mesalab.tool.utils.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/protocol/ProtocolTree.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/protocol/ProtocolTree.java
index d917798..0492b99 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/protocol/ProtocolTree.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/protocol/ProtocolTree.java
@@ -2,7 +2,7 @@ package com.mesalab.qgw.model.protocol;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/ArangoHealthIndicator.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/ArangoHealthIndicator.java
index 042d503..a04a299 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/ArangoHealthIndicator.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/ArangoHealthIndicator.java
@@ -7,8 +7,8 @@ import com.mesalab.knowledge.common.utils.Constant;
import com.mesalab.knowledge.common.utils.JwtCache;
import com.mesalab.knowledge.strategy.QueryProvider;
import com.mesalab.qgw.service.impl.HttpClientService;
-import com.zdjizhi.utils.JsonMapper;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.JsonMapper;
+import com.mesalab.tool.utils.StringUtil;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/ApiServiceImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/ApiServiceImpl.java
index b191734..89c1902 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/ApiServiceImpl.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/ApiServiceImpl.java
@@ -33,7 +33,7 @@ import com.mesalab.qgw.model.api.udf.UDF;
import com.mesalab.qgw.model.api.udf.UDFElements;
import com.mesalab.qgw.service.ApiService;
import com.mesalab.qgw.service.MetadataService;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Expression;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/HttpClientService.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/HttpClientService.java
index 6e21a2f..9bf422e 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/HttpClientService.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/HttpClientService.java
@@ -3,7 +3,7 @@ package com.mesalab.qgw.service.impl;
import com.google.common.collect.Maps;
import com.mesalab.common.exception.BusinessException;
import com.mesalab.knowledge.common.utils.HttpConfig;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/MetadataServiceImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/MetadataServiceImpl.java
index e65b328..0e4cd3f 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/MetadataServiceImpl.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/MetadataServiceImpl.java
@@ -10,8 +10,8 @@ import com.mesalab.common.enums.DBTypeEnum;
import com.mesalab.common.exception.BusinessException;
import com.mesalab.common.utils.SchemaCacheUtils;
import com.mesalab.qgw.service.MetadataService;
-import com.zdjizhi.utils.JsonMapper;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.JsonMapper;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.avro.Schema;
import org.apache.http.HttpStatus;
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/SystemServiceImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/SystemServiceImpl.java
index a36c0f5..463916d 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/SystemServiceImpl.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/SystemServiceImpl.java
@@ -16,9 +16,9 @@ import com.mesalab.qgw.model.job.StorageDeletionInfo;
import com.mesalab.qgw.model.job.XxlJobInfo;
import com.mesalab.qgw.service.ApiService;
import com.mesalab.qgw.service.SystemService;
-import com.zdjizhi.utils.DateUtils;
-import com.zdjizhi.utils.Encodes;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.DateUtils;
+import com.mesalab.tool.utils.Encodes;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
@@ -280,7 +280,7 @@ public class SystemServiceImpl implements SystemService {
StorageDeletionInfo storageDeletionInfo = new StorageDeletionInfo();
Map trafficDate = getDataByHandler(jobHandlerValue);
XxlJobInfo xxlJobInfo = mapToBean(trafficDate, XxlJobInfo.class);
- Map executorParam = (Map) com.zdjizhi.utils.JsonMapper.fromJsonString(xxlJobInfo.getExecutorParam(), Map.class);
+ Map executorParam = (Map) com.mesalab.tool.utils.JsonMapper.fromJsonString(xxlJobInfo.getExecutorParam(), Map.class);
Object maxDays = executorParam.get("maxdays");
storageDeletionInfo.setLogType(logType);
storageDeletionInfo.setMaxDays(Integer.parseInt(String.valueOf(maxDays)));
@@ -336,7 +336,7 @@ public class SystemServiceImpl implements SystemService {
baseResult = BaseResultGenerator.failure(HttpStatus.SC_INTERNAL_SERVER_ERROR, "服务繁忙,请联系调度平台方!");
} else {
if (resultMap.get("status").equals(String.valueOf(HttpStatus.SC_OK))) {
- Map result = (Map) com.zdjizhi.utils.JsonMapper.fromJsonString(String.valueOf(resultMap.get("result")), Map.class);
+ Map result = (Map) com.mesalab.tool.utils.JsonMapper.fromJsonString(String.valueOf(resultMap.get("result")), Map.class);
if (result.get("code").equals(HttpStatus.SC_OK)) {
baseResult = BaseResultGenerator.success("ok", null);
} else if (result.get("code").equals(HttpStatus.SC_LOCKED)) {
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/TestSqlServiceImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/TestSqlServiceImpl.java
index 478214c..e0fc6bd 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/TestSqlServiceImpl.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/TestSqlServiceImpl.java
@@ -12,8 +12,8 @@ import com.mesalab.common.utils.JsonMapper;
import com.mesalab.common.utils.SchemaCacheUtils;
import com.mesalab.knowledge.common.utils.HttpConfig;
import com.mesalab.qgw.model.api.ClickHouseHttpSource;
-import com.zdjizhi.utils.Encodes;
-import com.zdjizhi.utils.StringUtil;
+import com.mesalab.tool.utils.Encodes;
+import com.mesalab.tool.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.avro.JsonProperties;
import org.apache.avro.Schema;
@@ -456,7 +456,7 @@ public class TestSqlServiceImpl {
Iterator<String> iterator = name.iterator();
while (iterator.hasNext()) {//遍历表,以Avro为基础
String tableName = iterator.next();
- Map resultMap = (Map) com.zdjizhi.utils.JsonMapper.fromJsonString(String.valueOf(druidSchemaInfo.get(tableName)), Map.class);
+ Map resultMap = (Map) com.mesalab.tool.utils.JsonMapper.fromJsonString(String.valueOf(druidSchemaInfo.get(tableName)), Map.class);
if (resultMap == null) {
throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "schema未注册此表: " + tableName, null);
}
@@ -498,7 +498,7 @@ public class TestSqlServiceImpl {
Iterator<String> iterator = name.iterator();
while (iterator.hasNext()) {//遍历表,以Avro为基础
String tableName = iterator.next();
- Map resultMap = (Map) com.zdjizhi.utils.JsonMapper.fromJsonString(String.valueOf(ckSchemaInfo.get(tableName)), Map.class);
+ Map resultMap = (Map) com.mesalab.tool.utils.JsonMapper.fromJsonString(String.valueOf(ckSchemaInfo.get(tableName)), Map.class);
if (resultMap == null) {
throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "schema未注册此表: " + tableName, null);
}
@@ -587,7 +587,7 @@ public class TestSqlServiceImpl {
Iterator<String> iterator = name.iterator();
while (iterator.hasNext()) {//遍历表
String tableName = iterator.next();
- Map resultMap = (Map) com.zdjizhi.utils.JsonMapper.fromJsonString(String.valueOf(ckeckSchemaInfo.get(tableName)), Map.class);
+ Map resultMap = (Map) com.mesalab.tool.utils.JsonMapper.fromJsonString(String.valueOf(ckeckSchemaInfo.get(tableName)), Map.class);
if (resultMap == null) {
throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "schema未注册此表: " + tableName, null);
}
@@ -597,7 +597,7 @@ public class TestSqlServiceImpl {
while (fieldsIterator.hasNext()) {
Map next = fieldsIterator.next();
try {
- mapDoc = (Map) com.zdjizhi.utils.JsonMapper.fromJsonString(String.valueOf(next.get("doc")), Map.class);
+ mapDoc = (Map) com.mesalab.tool.utils.JsonMapper.fromJsonString(String.valueOf(next.get("doc")), Map.class);
} catch (Exception ex) {
log.error("该字段的 doc 为非JSON字符串,不需类型转换");
String str = String.format("%s.avro中doc非json格式字段%s", tableName, next.get("name"));
diff --git a/galaxy-tool/pom.xml b/galaxy-tool/pom.xml
new file mode 100644
index 0000000..daa5b13
--- /dev/null
+++ b/galaxy-tool/pom.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+ <parent>
+ <artifactId>galaxy-data-platform</artifactId>
+ <groupId>com.mesalab</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>galaxy-tool</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.4</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+ <dependency>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ <version>2.10</version>
+ </dependency>
+ <dependency>
+ <groupId>com.maxmind.geoip</groupId>
+ <artifactId>geoip-api</artifactId>
+ <version>1.3.1</version>
+ </dependency>
+ <dependency>
+ <groupId>com.maxmind.geoip2</groupId>
+ <artifactId>geoip2</artifactId>
+ <version>2.12.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.maxmind.db</groupId>
+ <artifactId>maxmind-db</artifactId>
+ <version>1.2.2</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.zookeeper</groupId>
+ <artifactId>zookeeper</artifactId>
+ <version>3.4.9</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>23.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.amazonaws</groupId>
+ <artifactId>aws-java-sdk</artifactId>
+ <version>${aws-java-sdk.version}</version>
+ </dependency>
+ </dependencies>
+
+</project> \ No newline at end of file
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/crypt/AESUtil.java b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/AESUtil.java
new file mode 100644
index 0000000..0072a23
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/AESUtil.java
@@ -0,0 +1,156 @@
+/*
+ * @(#)AESUtil.java 1.0
+ *
+ * Copyright 2010 NIS, Inc. All rights reserved.
+ *
+ */
+package com.mesalab.tool.crypt;
+ import java.security.Key;
+
+ import javax.crypto.Cipher;
+ import javax.crypto.KeyGenerator;
+ import javax.crypto.SecretKey;
+ import javax.crypto.spec.SecretKeySpec;
+
+ import org.apache.commons.codec.binary.Base64;
+ import org.apache.commons.codec.digest.DigestUtils;
+
+ /**
+ *
+ * <p>AES对称加密算法,组件类 </p>
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2013-07-10
+ *
+ */
+ public abstract class AESUtil {
+ //密钥算法
+ public static final String ALGORITHM="AES";
+ //密钥长度(java默认只能处理128位以内的长度,如果需要处理大于128位可以使用JCE解除密钥长度限制)
+ public static final int KEY_SIZE=128;
+ /**
+ * <p>转换密钥 </p>
+ * @param key 二进制密钥
+ * @return Key 密钥
+ * @throws Exception
+ */
+ private static Key toKey(byte[] key) throws Exception
+ {
+ //实例化AES密钥
+ SecretKey secretKey=new SecretKeySpec(key,ALGORITHM);
+ return secretKey;
+ }
+ /**
+ * <p>解密</p>
+ * @param data 待解密数据
+ * @param key 密钥
+ * @return byte[] 解密数据
+ * @throws Exception
+ */
+ public static byte[] decrypt(byte[] data,byte[] key) throws Exception
+ {
+ //还原密钥
+ Key k=toKey(key);
+ //实例化
+ Cipher cipher=Cipher.getInstance(ALGORITHM);
+ //初始化,设置为解密模式
+ cipher.init(Cipher.DECRYPT_MODE, k);
+ //执行操作
+ return cipher.doFinal(data);
+ }
+ /**
+ * <p>解密</p>
+ * @param data 待解密数据
+ * @param key 密钥
+ * @return byte[] 解密数据
+ * @throws Exception
+ */
+ public static byte[] decrypt(byte[] data,String key) throws Exception
+ {
+ return decrypt(data,getKey(key));
+ }
+ /**
+ * <p>加密</p>
+ * @param data 待加密数据
+ * @param key 密钥
+ * @return byte[] 加密数据
+ * @throws Exception
+ */
+ public static byte[] encrypt(byte[] data,byte[] key) throws Exception
+ {
+ //还原密钥
+ Key k=toKey(key);
+ //实例化
+ Cipher cipher=Cipher.getInstance(ALGORITHM);
+ //初始化,设置为加密模式
+ cipher.init(Cipher.ENCRYPT_MODE, k);
+ //执行操作
+ return cipher.doFinal(data);
+ }
+ /**
+ * <p>加密</p>
+ * @param data 待加密数据
+ * @param key 密钥
+ * @return byte[] 加密数据
+ * @throws Exception
+ */
+ public static byte[] encrypt(byte[] data,String key) throws Exception
+ {
+ return encrypt(data,getKey(key));
+ }
+ /**
+ * <p>生成密钥</p>
+ * @return byte[] 二进制密钥
+ * @throws Exception
+ */
+ public static byte[] initKey() throws Exception
+ {
+ //实例化
+ KeyGenerator kg=KeyGenerator.getInstance(ALGORITHM);
+ //初始化密钥长度
+ kg.init(KEY_SIZE);
+ //生成秘密密钥
+ SecretKey secretKey=kg.generateKey();
+ //获得密钥的二进制编码形式
+ return secretKey.getEncoded();
+ }
+ /**
+ * <p>初始化密钥</p>
+ * @return String Base64编码密钥
+ * @throws Exception
+ */
+ public static String initKeyString() throws Exception
+ {
+ return new String(Base64.encodeBase64(initKey()));
+ }
+ /**
+ * <p>获取密钥</p>
+ * @param key
+ * @return byte[] 密钥
+ * @throws Exception
+ */
+ public static byte[] getKey(String key) throws Exception
+ {
+ return Base64.decodeBase64(key.getBytes());
+ }
+ /**
+ * <p>摘要处理</p>
+ * @param data 待摘要数据
+ * @return String 摘要字符串
+ */
+ public static String shaHex(byte[] data)
+ {
+ return DigestUtils.md5Hex(data);
+ }
+ /**
+ * <p>摘要数据验证</p>
+ * @param data 待摘要数据
+ * @param messageDigest 摘要字符串
+ * @return 验证结果
+ */
+ public static boolean validate(byte[] data,String messageDigest)
+ {
+ return messageDigest.equals(shaHex(data));
+ }
+
+ }
+ \ No newline at end of file
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/crypt/BCrypt.java b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/BCrypt.java
new file mode 100644
index 0000000..ba61eb6
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/BCrypt.java
@@ -0,0 +1,775 @@
+package com.mesalab.tool.crypt;
+
+import java.io.UnsupportedEncodingException;
+import java.security.SecureRandom;
+/**
+ * BCrypt 加密,针对密码进行加密,针对salt原始密码,可每次生成hash值不同。通过checkpwd会自动验证密码是否正确。
+ * BCrypt implements OpenBSD-style Blowfish password hashing using
+ * the scheme described in "A Future-Adaptable Password Scheme" by
+ * Niels Provos and David Mazieres.
+ * <p>
+ * This password hashing system tries to thwart off-line password
+ * cracking using a computationally-intensive hashing algorithm,
+ * based on Bruce Schneier's Blowfish cipher. The work factor of
+ * the algorithm is parameterised, so it can be increased as
+ * computers get faster.
+ * <p>
+ * Usage is really simple. To hash a password for the first time,
+ * call the hashpw method with a random salt, like this:
+ * <p>
+ * <code>
+ * String pw_hash = BCrypt.hashpw(plain_password, BCrypt.gensalt());
+ * </code>
+ * <p>
+ * To check whether a plaintext password matches one that has been
+ * hashed previously, use the checkpw method:
+ * <p>
+ * <code>
+ * if (BCrypt.checkpw(candidate_password, stored_hash))
+ * &nbsp;&nbsp;&nbsp;&nbsp;System.out.println("It matches");
+ * else
+ * &nbsp;&nbsp;&nbsp;&nbsp;System.out.println("It does not match");
+ * </code>
+ * <p>
+ * The gensalt() method takes an optional parameter (log_rounds)
+ * that determines the computational complexity of the hashing:
+ * <p>
+ * <code>
+ * String strong_salt = BCrypt.gensalt(10)
+ * String stronger_salt = BCrypt.gensalt(12)
+ * </code>
+ * <p>
+ * The amount of work increases exponentially (2**log_rounds), so
+ * each increment is twice as much work. The default log_rounds is
+ * 10, and the valid range is 4 to 31.
+ *
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2011-05-31 下午13:28:28
+ */
+public class BCrypt {
+ // BCrypt parameters
+ private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10;
+ private static final int BCRYPT_SALT_LEN = 16;
+
+ // Blowfish parameters
+ private static final int BLOWFISH_NUM_ROUNDS = 16;
+
+ // Initial contents of key schedule
+ private static final int P_orig[] = {
+ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
+ 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
+ 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
+ 0x9216d5d9, 0x8979fb1b
+ };
+ private static final int S_orig[] = {
+ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
+ 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
+ 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
+ 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
+ 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
+ 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
+ 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
+ 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
+ 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
+ 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
+ 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
+ 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
+ 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
+ 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
+ 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
+ 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
+ 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
+ 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
+ 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
+ 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
+ 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
+ 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
+ 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
+ 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
+ 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
+ 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
+ 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
+ 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
+ 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
+ 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
+ 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
+ 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
+ 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
+ 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
+ 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
+ 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
+ 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
+ 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
+ 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
+ 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
+ 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
+ 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
+ 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
+ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
+ 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
+ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+ 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
+ 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
+ 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
+ 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
+ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+ 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
+ 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
+ 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
+ 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
+ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+ 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
+ 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
+ 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
+ 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
+ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+ 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
+ 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
+ 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
+ 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
+ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+ 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
+ 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
+ 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
+ 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
+ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+ 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
+ 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
+ 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
+ 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
+ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+ 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
+ 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
+ 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
+ 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
+ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+ 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
+ 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
+ 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
+ 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
+ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+ 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
+ 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
+ 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
+ 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
+ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+ 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
+ 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
+ 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
+ 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
+ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+ 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
+ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
+ 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
+ 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+ 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
+ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
+ 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
+ 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
+ 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+ 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
+ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
+ 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
+ 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
+ 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+ 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
+ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
+ 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
+ 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
+ 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+ 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
+ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
+ 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
+ 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
+ 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+ 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
+ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
+ 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
+ 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
+ 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+ 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
+ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
+ 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
+ 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
+ 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+ 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
+ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
+ 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
+ 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
+ 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+ 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
+ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
+ 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
+ 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
+ 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+ 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
+ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
+ 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
+ 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
+ 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+ 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
+ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
+ 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
+ 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
+ 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+ 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
+ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
+ 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
+ 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
+ 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
+ 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
+ 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
+ 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
+ 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
+ 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
+ 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
+ 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
+ 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
+ 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
+ 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
+ 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
+ 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
+ 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
+ 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
+ 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
+ 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
+ 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
+ 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
+ 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
+ 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
+ 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
+ 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
+ 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
+ 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
+ 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
+ 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
+ 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
+ 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
+ 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
+ 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
+ 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
+ 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
+ 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
+ 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
+ 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
+ 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
+ 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
+ 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
+ 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
+ };
+
+ // bcrypt IV: "OrpheanBeholderScryDoubt"
+ static private final int bf_crypt_ciphertext[] = {
+ 0x4f727068, 0x65616e42, 0x65686f6c,
+ 0x64657253, 0x63727944, 0x6f756274
+ };
+
+ // Table for Base64 encoding
+ static private final char base64_code[] = {
+ '.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+ 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+ 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
+ '6', '7', '8', '9'
+ };
+
+ // Table for Base64 decoding
+ static private final byte index_64[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 0, 1, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, -1, -1,
+ -1, -1, -1, -1, -1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ -1, -1, -1, -1, -1, -1, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, -1, -1, -1, -1, -1
+ };
+
+ // Expanded Blowfish key
+ private int P[];
+ private int S[];
+
+ /**
+ * Encode a byte array using bcrypt's slightly-modified base64
+ * encoding scheme. Note that this is *not* compatible with
+ * the standard MIME-base64 encoding.
+ *
+ * @param d the byte array to encode
+ * @param len the number of bytes to encode
+ * @return base64-encoded string
+ * @exception IllegalArgumentException if the length is invalid
+ */
+ private static String encode_base64(byte d[], int len)
+ throws IllegalArgumentException {
+ int off = 0;
+ StringBuffer rs = new StringBuffer();
+ int c1, c2;
+
+ if (len <= 0 || len > d.length) {
+ throw new IllegalArgumentException ("Invalid len");
+ }
+
+
+ while (off < len) {
+ c1 = d[off++] & 0xff;
+ rs.append(base64_code[(c1 >> 2) & 0x3f]);
+ c1 = (c1 & 0x03) << 4;
+ if (off >= len) {
+ rs.append(base64_code[c1 & 0x3f]);
+ break;
+ }
+ c2 = d[off++] & 0xff;
+ c1 |= (c2 >> 4) & 0x0f;
+ rs.append(base64_code[c1 & 0x3f]);
+ c1 = (c2 & 0x0f) << 2;
+ if (off >= len) {
+ rs.append(base64_code[c1 & 0x3f]);
+ break;
+ }
+ c2 = d[off++] & 0xff;
+ c1 |= (c2 >> 6) & 0x03;
+ rs.append(base64_code[c1 & 0x3f]);
+ rs.append(base64_code[c2 & 0x3f]);
+ }
+ return rs.toString();
+ }
+
+ /**
+ * Look up the 3 bits base64-encoded by the specified character,
+ * range-checking againt conversion table
+ * @param x the base64-encoded value
+ * @return the decoded value of x
+ */
+ private static byte char64(char x) {
+ if ((int)x < 0 || (int)x > index_64.length) {
+ return -1;
+ }
+
+ return index_64[(int)x];
+ }
+
+ /**
+ * Decode a string encoded using bcrypt's base64 scheme to a
+ * byte array. Note that this is *not* compatible with
+ * the standard MIME-base64 encoding.
+ * @param s the string to decode
+ * @param maxolen the maximum number of bytes to decode
+ * @return an array containing the decoded bytes
+ * @throws IllegalArgumentException if maxolen is invalid
+ */
+ private static byte[] decode_base64(String s, int maxolen)
+ throws IllegalArgumentException {
+ StringBuffer rs = new StringBuffer();
+ int off = 0, slen = s.length(), olen = 0;
+ byte ret[];
+ byte c1, c2, c3, c4, o;
+
+ if (maxolen <= 0) {
+ throw new IllegalArgumentException ("Invalid maxolen");
+ }
+
+
+ while (off < slen - 1 && olen < maxolen) {
+ c1 = char64(s.charAt(off++));
+ c2 = char64(s.charAt(off++));
+ if (c1 == -1 || c2 == -1) {
+ break;
+ }
+
+ o = (byte)(c1 << 2);
+ o |= (c2 & 0x30) >> 4;
+ rs.append((char)o);
+ if (++olen >= maxolen || off >= slen) {
+ break;
+ }
+
+ c3 = char64(s.charAt(off++));
+ if (c3 == -1) {
+ break;
+ }
+
+ o = (byte)((c2 & 0x0f) << 4);
+ o |= (c3 & 0x3c) >> 2;
+ rs.append((char)o);
+ if (++olen >= maxolen || off >= slen) {
+ break;
+ }
+
+ c4 = char64(s.charAt(off++));
+ o = (byte)((c3 & 0x03) << 6);
+ o |= c4;
+ rs.append((char)o);
+ ++olen;
+ }
+
+ ret = new byte[olen];
+ for (off = 0; off < olen; off++) {
+ ret[off] = (byte)rs.charAt(off);
+ }
+
+ return ret;
+ }
+
+ /**
+ * Blowfish encipher a single 64-bit block encoded as
+ * two 32-bit halves
+ * @param lr an array containing the two 32-bit half blocks
+ * @param off the position in the array of the blocks
+ */
+ private final void encipher(int lr[], int off) {
+ int i, n, l = lr[off], r = lr[off + 1];
+
+ l ^= P[0];
+ for (i = 0; i <= BLOWFISH_NUM_ROUNDS - 2;) {
+ // Feistel substitution on left word
+ n = S[(l >> 24) & 0xff];
+ n += S[0x100 | ((l >> 16) & 0xff)];
+ n ^= S[0x200 | ((l >> 8) & 0xff)];
+ n += S[0x300 | (l & 0xff)];
+ r ^= n ^ P[++i];
+
+ // Feistel substitution on right word
+ n = S[(r >> 24) & 0xff];
+ n += S[0x100 | ((r >> 16) & 0xff)];
+ n ^= S[0x200 | ((r >> 8) & 0xff)];
+ n += S[0x300 | (r & 0xff)];
+ l ^= n ^ P[++i];
+ }
+ lr[off] = r ^ P[BLOWFISH_NUM_ROUNDS + 1];
+ lr[off + 1] = l;
+ }
+
+ /**
+ * Cycically extract a word of key material
+ * @param data the string to extract the data from
+ * @param offp a "pointer" (as a one-entry array) to the
+ * current offset into data
+ * @return the next word of material from data
+ */
+ private static int streamtoword(byte data[], int offp[]) {
+ int i;
+ int word = 0;
+ int off = offp[0];
+
+ for (i = 0; i < 4; i++) {
+ word = (word << 8) | (data[off] & 0xff);
+ off = (off + 1) % data.length;
+ }
+
+ offp[0] = off;
+ return word;
+ }
+
+ /**
+ * Initialise the Blowfish key schedule
+ */
+ private void init_key() {
+ P = (int[])P_orig.clone();
+ S = (int[])S_orig.clone();
+ }
+
+ /**
+ * Key the Blowfish cipher
+ * @param key an array containing the key
+ */
+ private void key(byte key[]) {
+ int i;
+ int koffp[] = { 0 };
+ int lr[] = { 0, 0 };
+ int plen = P.length, slen = S.length;
+
+ for (i = 0; i < plen; i++) {
+ P[i] = P[i] ^ streamtoword(key, koffp);
+ }
+
+
+ for (i = 0; i < plen; i += 2) {
+ encipher(lr, 0);
+ P[i] = lr[0];
+ P[i + 1] = lr[1];
+ }
+
+ for (i = 0; i < slen; i += 2) {
+ encipher(lr, 0);
+ S[i] = lr[0];
+ S[i + 1] = lr[1];
+ }
+ }
+
+ /**
+ * Perform the "enhanced key schedule" step described by
+ * Provos and Mazieres in "A Future-Adaptable Password Scheme"
+ * http://www.openbsd.org/papers/bcrypt-paper.ps
+ * @param data salt information
+ * @param key password information
+ */
+ private void ekskey(byte data[], byte key[]) {
+ int i;
+ int koffp[] = { 0 }, doffp[] = { 0 };
+ int lr[] = { 0, 0 };
+ int plen = P.length, slen = S.length;
+
+ for (i = 0; i < plen; i++) {
+ P[i] = P[i] ^ streamtoword(key, koffp);
+ }
+
+
+ for (i = 0; i < plen; i += 2) {
+ lr[0] ^= streamtoword(data, doffp);
+ lr[1] ^= streamtoword(data, doffp);
+ encipher(lr, 0);
+ P[i] = lr[0];
+ P[i + 1] = lr[1];
+ }
+
+ for (i = 0; i < slen; i += 2) {
+ lr[0] ^= streamtoword(data, doffp);
+ lr[1] ^= streamtoword(data, doffp);
+ encipher(lr, 0);
+ S[i] = lr[0];
+ S[i + 1] = lr[1];
+ }
+ }
+
+ /**
+ * Perform the central password hashing step in the
+ * bcrypt scheme
+ * @param password the password to hash
+ * @param salt the binary salt to hash with the password
+ * @param log_rounds the binary logarithm of the number
+ * of rounds of hashing to apply
+ * @return an array containing the binary hashed password
+ */
+ private byte[] crypt_raw(byte password[], byte salt[], int log_rounds) {
+ int rounds, i, j;
+ int cdata[] = (int[])bf_crypt_ciphertext.clone();
+ int clen = cdata.length;
+ byte ret[];
+
+ if (log_rounds < 4 || log_rounds > 31) {
+ throw new IllegalArgumentException ("Bad number of rounds");
+ }
+
+ rounds = 1 << log_rounds;
+ if (salt.length != BCRYPT_SALT_LEN) {
+ throw new IllegalArgumentException ("Bad salt length");
+ }
+
+
+ init_key();
+ ekskey(salt, password);
+ for (i = 0; i < rounds; i++) {
+ key(password);
+ key(salt);
+ }
+
+ for (i = 0; i < 64; i++) {
+ for (j = 0; j < (clen >> 1); j++) {
+ encipher(cdata, j << 1);
+ }
+
+ }
+
+ ret = new byte[clen * 4];
+ for (i = 0, j = 0; i < clen; i++) {
+ ret[j++] = (byte)((cdata[i] >> 24) & 0xff);
+ ret[j++] = (byte)((cdata[i] >> 16) & 0xff);
+ ret[j++] = (byte)((cdata[i] >> 8) & 0xff);
+ ret[j++] = (byte)(cdata[i] & 0xff);
+ }
+ return ret;
+ }
+
+ /**
+ * Hash a password using the OpenBSD bcrypt scheme
+ * @param password the password to hash
+ * @param salt the salt to hash with (perhaps generated
+ * using BCrypt.gensalt)
+ * @return the hashed password
+ */
+ public static String hashpw(String password, String salt) {
+ BCrypt B;
+ String real_salt;
+ byte passwordb[], saltb[], hashed[];
+ char minor = (char)0;
+ int rounds, off = 0;
+ StringBuffer rs = new StringBuffer();
+
+ if (salt.charAt(0) != '$' || salt.charAt(1) != '2') {
+ throw new IllegalArgumentException ("Invalid salt version");
+ }
+
+ if (salt.charAt(2) == '$') {
+ off = 3;
+ } else {
+ minor = salt.charAt(2);
+ if (minor != 'a' || salt.charAt(3) != '$') {
+ throw new IllegalArgumentException ("Invalid salt revision");
+ }
+
+ off = 4;
+ }
+
+ // Extract number of rounds
+ if (salt.charAt(off + 2) > '$') {
+ throw new IllegalArgumentException ("Missing salt rounds");
+ }
+
+ rounds = Integer.parseInt(salt.substring(off, off + 2));
+
+ real_salt = salt.substring(off + 3, off + 25);
+ try {
+ passwordb = (password + (minor >= 'a' ? "\000" : "")).getBytes("UTF-8");
+ } catch (UnsupportedEncodingException uee) {
+ throw new AssertionError("UTF-8 is not supported");
+ }
+
+ saltb = decode_base64(real_salt, BCRYPT_SALT_LEN);
+
+ B = new BCrypt();
+ hashed = B.crypt_raw(passwordb, saltb, rounds);
+
+ rs.append("$2");
+ if (minor >= 'a') {
+ rs.append(minor);
+ }
+
+ rs.append("$");
+ if (rounds < 10) {
+ rs.append("0");
+ }
+
+ rs.append(Integer.toString(rounds));
+ rs.append("$");
+ rs.append(encode_base64(saltb, saltb.length));
+ rs.append(encode_base64(hashed,
+ bf_crypt_ciphertext.length * 4 - 1));
+ return rs.toString();
+ }
+
+ /**
+ * Generate a salt for use with the BCrypt.hashpw() method
+ * @param log_rounds the log2 of the number of rounds of
+ * hashing to apply - the work factor therefore increases as
+ * 2**log_rounds.
+ * @param random an instance of SecureRandom to use
+ * @return an encoded salt value
+ */
+ public static String gensalt(int log_rounds, SecureRandom random) {
+ StringBuffer rs = new StringBuffer();
+ byte rnd[] = new byte[BCRYPT_SALT_LEN];
+
+ random.nextBytes(rnd);
+
+ rs.append("$2a$");
+ if (log_rounds < 10) {
+ rs.append("0");
+ }
+
+ rs.append(Integer.toString(log_rounds));
+ rs.append("$");
+ rs.append(encode_base64(rnd, rnd.length));
+ return rs.toString();
+ }
+
+ /**
+ * Generate a salt for use with the BCrypt.hashpw() method
+ * @param log_rounds the log2 of the number of rounds of
+ * hashing to apply - the work factor therefore increases as
+ * 2**log_rounds.
+ * @return an encoded salt value
+ */
+ public static String gensalt(int log_rounds) {
+ return gensalt(log_rounds, new SecureRandom());
+ }
+
+ /**
+ * Generate a salt for use with the BCrypt.hashpw() method,
+ * selecting a reasonable default for the number of hashing
+ * rounds to apply
+ * @return an encoded salt value
+ */
+ public static String gensalt() {
+ return gensalt(GENSALT_DEFAULT_LOG2_ROUNDS);
+ }
+
+ /**
+ * Check that a plaintext password matches a previously hashed
+ * one
+ * @param plaintext the plaintext password to verify
+ * @param hashed the previously-hashed password
+ * @return true if the passwords match, false otherwise
+ */
+ public static boolean checkpw(String plaintext, String hashed) {
+ return (hashed.compareTo(hashpw(plaintext, hashed)) == 0);
+ }
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/crypt/CertificateCoder.java b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/CertificateCoder.java
new file mode 100644
index 0000000..2292fbe
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/CertificateCoder.java
@@ -0,0 +1,214 @@
+
+ package com.mesalab.tool.crypt;
+
+ import java.io.FileInputStream;
+ import java.security.KeyStore;
+ import java.security.PrivateKey;
+ import java.security.PublicKey;
+ import java.security.Signature;
+ import java.security.cert.Certificate;
+ import java.security.cert.CertificateFactory;
+ import java.security.cert.X509Certificate;
+
+ import javax.crypto.Cipher;
+
+ /**
+ *
+ * <p>X.509证书组件</p>
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2013-07-10
+ *
+ */
+ public abstract class CertificateCoder {
+ //类型证书
+ private static final String CERT_TYPE="X.509";
+ /**
+ * 由KeyStore获得私钥
+ * @param keyStorePath 密钥库路径
+ * @param alias 别名
+ * @param password 密码
+ * @return PrivateKey 密钥
+ * @throws Exception
+ */
+ private static PrivateKey getPrivateKeyByKeyStore(String keyStorePath,String alias,String password) throws Exception
+ {
+ //获得密钥库
+ KeyStore ks=getKeyStore(keyStorePath,password);
+ //获得私钥
+ return (PrivateKey)ks.getKey(alias, password.toCharArray());
+ }
+ /**
+ * 由Certificate获得公钥
+ * @param certificatePath 证书路径
+ * @return PublicKey 公钥
+ */
+ private static PublicKey getPublicKeyByCertificate(String certificatePath) throws Exception
+ {
+ //获得证书
+ Certificate certificate=getCertificate(certificatePath);
+ //获得公钥
+ return certificate.getPublicKey();
+ }
+ /**
+ * 获得certificate
+ * @param certificatePath 证书路径
+ * @return Certificate 证书
+ * @throws Exception
+ */
+ private static Certificate getCertificate(String certificatePath) throws Exception
+ {
+ //实例化证书工厂
+ CertificateFactory certificateFactory=CertificateFactory.getInstance(CERT_TYPE);
+ //取得证书文件流
+ FileInputStream in=new FileInputStream(certificatePath);
+ //生成证书
+ Certificate certificate=certificateFactory.generateCertificate(in);
+ //关闭证书文件流
+ in.close();
+ return certificate;
+ }
+ /**
+ * 取得Certificate
+ * @param keyStorePath 密钥库路径
+ * @param alias 别名
+ * @param password 密码
+ * @return Certificate 证书
+ * @throws Exception
+ */
+ private static Certificate getCertificate(String keyStorePath,String alias,String password) throws Exception
+ {
+ //获得密钥库
+ KeyStore ks=getKeyStore(keyStorePath,password);
+ //获得证书
+ return ks.getCertificate(alias);
+ }
+ /**
+ * 获得密钥库
+ * @param keyStorePath 密钥库路径
+ * @param password 密码
+ * @return KeyStore 密钥库
+ * @throws Exception
+ */
+ private static KeyStore getKeyStore(String keyStorePath,String password) throws Exception
+ {
+ //实例化密钥库
+ KeyStore ks=KeyStore.getInstance(KeyStore.getDefaultType());
+ //获得密钥库文件流
+ FileInputStream in=new FileInputStream(keyStorePath);
+ //加载密钥库
+ ks.load(in, password.toCharArray());
+ //关闭密钥库文件流
+ in.close();
+ return ks;
+ }
+ /**
+ * 私钥加密
+ * @param data 待加密数据
+ * @param keyStorePath 密钥库路径
+ * @param alias 别名
+ * @param password 密码
+ * @return byte[] 加密数据
+ * @throws Exception
+ */
+ public static byte[] encryptByPrivateKey(byte[] data,String keyStorePath,String alias,String password) throws Exception
+ {
+ //取得私钥
+ PrivateKey privateKey=getPrivateKeyByKeyStore(keyStorePath,alias,password);
+ //对数据加密
+ Cipher cipher=Cipher.getInstance(privateKey.getAlgorithm());
+ cipher.init(Cipher.ENCRYPT_MODE, privateKey);
+ return cipher.doFinal(data);
+ }
+ /**
+ * 私钥解密
+ * @param data 待解密数据
+ * @param keyStorePath 密钥库路径
+ * @param alias 别名
+ * @param password 密码
+ * @return byte[] 加密数据
+ * @throws Exception
+ */
+ public static byte[] decryptByPrivateKey(byte[] data,String keyStorePath,String alias,String password) throws Exception
+ {
+ //取得私钥
+ PrivateKey privateKey=getPrivateKeyByKeyStore(keyStorePath,alias,password);
+ //对数据解密
+ Cipher cipher=Cipher.getInstance(privateKey.getAlgorithm());
+ cipher.init(Cipher.DECRYPT_MODE, privateKey);
+ return cipher.doFinal(data);
+ }
+ /**
+ * 公钥加密
+ * @param data 待加密数据
+ * @param certificatePath 证书路径
+ * @return byte[] 加密数据
+ * @throws Exception
+ */
+ public static byte[] encryptByPublicKey(byte[] data,String certificatePath) throws Exception
+ {
+ //取得公钥
+ PublicKey publicKey=getPublicKeyByCertificate(certificatePath);
+ //对数据加密
+ Cipher cipher=Cipher.getInstance(publicKey.getAlgorithm());
+ cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+ return cipher.doFinal(data);
+ }
+ /**
+ * 公钥解密
+ * @param data 待解密数据
+ * @param certificatePath 证书路径
+ * @return byte[] 解密数据
+ * @throws Exception
+ */
+ public static byte[] decryptByPublicKey(byte[] data,String certificatePath) throws Exception
+ {
+ //取得公钥
+ PublicKey publicKey=getPublicKeyByCertificate(certificatePath);
+ //对数据解密
+ Cipher cipher=Cipher.getInstance(publicKey.getAlgorithm());
+ cipher.init(Cipher.DECRYPT_MODE, publicKey);
+ return cipher.doFinal(data);
+ }
+ /**
+ * 签名
+ * @param data 待签名数据
+ * @param keyStorePath 密钥库路径
+ * @param alias 别名
+ * @param password 密码
+ * @return byte[] 签名
+ * @throws Exception
+ */
+ public static byte[] sign(byte[] data,String keyStorePath,String alias,String password) throws Exception
+ {
+ //获得证书
+ X509Certificate x509Certificate=(X509Certificate)getCertificate(keyStorePath,alias,password);
+ //构建签名,由证书指定签名算法
+ Signature signature=Signature.getInstance(x509Certificate.getSigAlgName());
+ //获取私钥
+ PrivateKey privateKey=getPrivateKeyByKeyStore(keyStorePath, alias, password);
+ //初始化签名,由私钥构建
+ signature.initSign(privateKey);
+ signature.update(data);
+ return signature.sign();
+ }
+ /**
+ * 签名验证
+ * @param data 数据
+ * @param sign 签名
+ * @param certificatePath 证书路径
+ * @return boolean 验证通过为true
+ * @throws Exception
+ */
+ public static boolean verify(byte[] data,byte[] sign,String certificatePath) throws Exception
+ {
+ //获得证书
+ X509Certificate x509Certificate=(X509Certificate)getCertificate(certificatePath);
+ //构建签名,由证书指定签名算法
+ Signature signature=Signature.getInstance(x509Certificate.getSigAlgName());
+ //由证书初始化签名,实际上是使用了证书中的公钥
+ signature.initVerify(x509Certificate);
+ signature.update(data);
+ return signature.verify(sign);
+ }
+ }
+ \ No newline at end of file
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/crypt/Cryptos.java b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/Cryptos.java
new file mode 100644
index 0000000..549b95a
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/Cryptos.java
@@ -0,0 +1,257 @@
+package com.mesalab.tool.crypt;
+
+import com.mesalab.tool.exception.Exceptions;
+import com.mesalab.tool.utils.Encodes;
+
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * 支持HMAC-SHA1消息签名 及 DES/AES对称加密的工具类.
+ *
+ * 支持Hex与Base64两种编码方式.
+ *
+ * @author
+ */
+public class Cryptos {
+
+ private static final String AES = "AES";
+ private static final String AES_CBC = "AES/CBC/PKCS5Padding";
+ private static final String HMACSHA1 = "HmacSHA1";
+
+ private static final String DEFAULT_URL_ENCODING = "UTF-8";
+ private static final int DEFAULT_HMACSHA1_KEYSIZE = 160; //RFC2401
+ private static final int DEFAULT_AES_KEYSIZE = 128;
+ private static final int DEFAULT_IVSIZE = 16;
+
+ private static final byte[] DEFAULT_KEY = new byte[]{-97,88,-94,9,70,-76,126,25,0,3,-20,113,108,28,69,125};
+
+ private static SecureRandom random = new SecureRandom();
+
+ //-- HMAC-SHA1 funciton --//
+ /**
+ * 使用HMAC-SHA1进行消息签名, 返回字节数组,长度为20字节.
+ *
+ * @param input 原始输入字符数组
+ * @param key HMAC-SHA1密钥
+ */
+ public static byte[] hmacSha1(byte[] input, byte[] key) {
+ try {
+ SecretKey secretKey = new SecretKeySpec(key, HMACSHA1);
+ Mac mac = Mac.getInstance(HMACSHA1);
+ mac.init(secretKey);
+ return mac.doFinal(input);
+ } catch (GeneralSecurityException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+ /**
+ * 校验HMAC-SHA1签名是否正确.
+ *
+ * @param expected 已存在的签名
+ * @param input 原始输入字符串
+ * @param key 密钥
+ */
+ public static boolean isMacValid(byte[] expected, byte[] input, byte[] key) {
+ byte[] actual = hmacSha1(input, key);
+ return Arrays.equals(expected, actual);
+ }
+
+ /**
+ * 生成HMAC-SHA1密钥,返回字节数组,长度为160位(20字节).
+ * HMAC-SHA1算法对密钥无特殊要求, RFC2401建议最少长度为160位(20字节).
+ */
+ public static byte[] generateHmacSha1Key() {
+ try {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(HMACSHA1);
+ keyGenerator.init(DEFAULT_HMACSHA1_KEYSIZE);
+ SecretKey secretKey = keyGenerator.generateKey();
+ return secretKey.getEncoded();
+ } catch (GeneralSecurityException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+ //-- AES funciton --//
+
+ /**
+ * 使用AES加密原始字符串.
+ *
+ * @param input 原始输入字符数组
+ */
+ public static String aesEncrypt(String input) {
+ try {
+ return Encodes.encodeHex(aesEncrypt(input.getBytes(DEFAULT_URL_ENCODING), DEFAULT_KEY));
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ }
+
+ /**
+ * 使用AES加密原始字符串.
+ *
+ * @param input 原始输入字符数组
+ * @param key 符合AES要求的密钥
+ */
+ public static String aesEncrypt(String input, String key) {
+ try {
+ return Encodes.encodeHex(aesEncrypt(input.getBytes(DEFAULT_URL_ENCODING), Encodes.decodeHex(key)));
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ }
+
+ /**
+ * 使用AES加密原始字符串.
+ *
+ * @param input 原始输入字符数组
+ * @param key 符合AES要求的密钥
+ */
+ public static byte[] aesEncrypt(byte[] input, byte[] key) {
+ return aes(input, key, Cipher.ENCRYPT_MODE);
+ }
+
+ /**
+ * 使用AES加密原始字符串.
+ *
+ * @param input 原始输入字符数组
+ * @param key 符合AES要求的密钥
+ * @param iv 初始向量
+ */
+ public static byte[] aesEncrypt(byte[] input, byte[] key, byte[] iv) {
+ return aes(input, key, iv, Cipher.ENCRYPT_MODE);
+ }
+
+ /**
+ * 使用AES解密字符串, 返回原始字符串.
+ *
+ * @param input Hex编码的加密字符串
+ */
+ public static String aesDecrypt(String input) {
+ try {
+ return new String(aesDecrypt(Encodes.decodeHex(input), DEFAULT_KEY), DEFAULT_URL_ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ }
+
+ /**
+ * 使用AES解密字符串, 返回原始字符串.
+ *
+ * @param input Hex编码的加密字符串
+ * @param key 符合AES要求的密钥
+ */
+ public static String aesDecrypt(String input, String key) {
+ try {
+ return new String(aesDecrypt(Encodes.decodeHex(input), Encodes.decodeHex(key)), DEFAULT_URL_ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ }
+
+ /**
+ * 使用AES解密字符串, 返回原始字符串.
+ *
+ * @param input Hex编码的加密字符串
+ * @param key 符合AES要求的密钥
+ */
+ public static byte[] aesDecrypt(byte[] input, byte[] key) {
+ return aes(input, key, Cipher.DECRYPT_MODE);
+ }
+
+ /**
+ * 使用AES解密字符串, 返回原始字符串.
+ *
+ * @param input Hex编码的加密字符串
+ * @param key 符合AES要求的密钥
+ * @param iv 初始向量
+ */
+ public static byte[] aesDecrypt(byte[] input, byte[] key, byte[] iv) {
+ return aes(input, key, iv, Cipher.DECRYPT_MODE);
+ }
+
+ /**
+ * 使用AES加密或解密无编码的原始字节数组, 返回无编码的字节数组结果.
+ *
+ * @param input 原始字节数组
+ * @param key 符合AES要求的密钥
+ * @param mode Cipher.ENCRYPT_MODE 或 Cipher.DECRYPT_MODE
+ */
+ private static byte[] aes(byte[] input, byte[] key, int mode) {
+ try {
+ SecretKey secretKey = new SecretKeySpec(key, AES);
+ Cipher cipher = Cipher.getInstance(AES);
+ cipher.init(mode, secretKey);
+ return cipher.doFinal(input);
+ } catch (GeneralSecurityException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+ /**
+ * 使用AES加密或解密无编码的原始字节数组, 返回无编码的字节数组结果.
+ *
+ * @param input 原始字节数组
+ * @param key 符合AES要求的密钥
+ * @param iv 初始向量
+ * @param mode Cipher.ENCRYPT_MODE 或 Cipher.DECRYPT_MODE
+ */
+ private static byte[] aes(byte[] input, byte[] key, byte[] iv, int mode) {
+ try {
+ SecretKey secretKey = new SecretKeySpec(key, AES);
+ IvParameterSpec ivSpec = new IvParameterSpec(iv);
+ Cipher cipher = Cipher.getInstance(AES_CBC);
+ cipher.init(mode, secretKey, ivSpec);
+ return cipher.doFinal(input);
+ } catch (GeneralSecurityException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+ /**
+ * 生成AES密钥,返回字节数组, 默认长度为128位(16字节).
+ */
+ public static String generateAesKeyString() {
+ return Encodes.encodeHex(generateAesKey(DEFAULT_AES_KEYSIZE));
+ }
+
+ /**
+ * 生成AES密钥,返回字节数组, 默认长度为128位(16字节).
+ */
+ public static byte[] generateAesKey() {
+ return generateAesKey(DEFAULT_AES_KEYSIZE);
+ }
+
+ /**
+ * 生成AES密钥,可选长度为128,192,256位.
+ */
+ public static byte[] generateAesKey(int keysize) {
+ try {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);
+ keyGenerator.init(keysize);
+ SecretKey secretKey = keyGenerator.generateKey();
+ return secretKey.getEncoded();
+ } catch (GeneralSecurityException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+ /**
+ * 生成随机向量,默认大小为cipher.getBlockSize(), 16字节.
+ */
+ public static byte[] generateIV() {
+ byte[] bytes = new byte[DEFAULT_IVSIZE];
+ random.nextBytes(bytes);
+ return bytes;
+ }
+} \ No newline at end of file
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/crypt/DesFileUtil.java b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/DesFileUtil.java
new file mode 100644
index 0000000..53da0b8
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/DesFileUtil.java
@@ -0,0 +1,124 @@
+package com.mesalab.tool.crypt;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.KeyGenerator;
+import java.io.*;
+import java.security.Key;
+import java.security.SecureRandom;
+
+/**
+ *
+ * <p>3des加密算法,针对文件进行加密的工具类 </p>
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2013-07-10
+ *
+ */
+public abstract class DesFileUtil {
+
+ /**
+ * <p>把成生的一对密钥保存到DesKey.xml文件中</p>
+ * @param keyFilePath 密钥文件,如果密钥文件不存在,将会建立该文件
+ * @throws FileNotFoundException
+ */
+ public static void saveDesKey(String keyFilePath) throws FileNotFoundException {
+ try {
+ File keyFile = new File(keyFilePath);
+ if(keyFile.isFile()&&!keyFile.exists()){
+ keyFile.createNewFile();
+ }
+ SecureRandom sr = new SecureRandom();
+ //为我们选择的DES算法生成一个KeyGenerator对象
+ KeyGenerator kg = KeyGenerator.getInstance ("DESede");
+ kg.init (sr);
+ FileOutputStream fos = new FileOutputStream(keyFile);
+ ObjectOutputStream oos = new ObjectOutputStream(fos);
+ //生成密钥
+ Key key = kg.generateKey();
+ oos.writeObject(key);
+ oos.close();
+ }catch (FileNotFoundException fe) {
+ throw new FileNotFoundException("keyFile is not found");
+ }catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * <p>获得DES加密的密钥</p>
+ * <pre>
+ * 在交易处理的过程中应该定时更
+ * 换密钥。需要JCE的支持,如果jdk版本低于1.4,则需要
+ * 安装jce-1_2_2才能正常使用。
+ * </pre>
+ * @param keyFilePath 已存在密钥文件
+ * @return Key 返回对称密钥
+ * @throws FileNotFoundException
+ */
+ public static Key getKey(String keyFilePath) throws FileNotFoundException {
+ Key kp = null;
+ try {
+ InputStream is = new FileInputStream(new File(keyFilePath));
+ ObjectInputStream oos = new ObjectInputStream(is);
+ kp = (Key) oos.readObject();
+ oos.close();
+ }catch (FileNotFoundException fe) {
+ throw new FileNotFoundException("keyFile is not found");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return kp;
+ }
+
+ /**
+ * <p>文件file进行加密并保存目标文件destFile中</p>
+ * @param file 要加密的文件 如c:/test/srcFile.txt
+ * @param destFile 加密后存放的文件名 如c:/加密后文件.txt
+ * @param keyFile 密钥文件
+ * @throws Exception
+ */
+ public static void encrypt(String file, String destFile,String keyFile) throws Exception {
+ Cipher cipher = Cipher.getInstance("DESede");
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(keyFile));
+ InputStream is = new FileInputStream(file);
+ OutputStream out = new FileOutputStream(destFile);
+ CipherInputStream cis = new CipherInputStream(is, cipher);
+ byte[] buffer = new byte[1024];
+ int r;
+ while ((r = cis.read(buffer)) > 0) {
+ out.write(buffer, 0, r);
+ }
+ cis.close();
+ is.close();
+ out.close();
+ }
+
+ /**
+ * <p>文件file进行加密并保存目标文件destFile中</p>
+ * @param file 已加密的文件 如c:/加密后文件.txt
+ * @param dest 解密后存放的文件名 如c:/ test/解密后文件.txt
+ * @param keyFile 密钥文件
+ * @throws Exception
+ */
+ public static void decrypt(String file, String dest,String keyFile) throws Exception {
+ Cipher cipher = Cipher.getInstance("DESede");
+ cipher.init(Cipher.DECRYPT_MODE, getKey(keyFile));
+ InputStream is = new FileInputStream(file);
+ OutputStream out = new FileOutputStream(dest);
+ CipherOutputStream cos = new CipherOutputStream(out, cipher);
+ byte[] buffer = new byte[1024];
+ int r;
+ while ((r = is.read(buffer)) >= 0) {
+ cos.write(buffer, 0, r);
+ }
+ cos.close();
+ out.close();
+ is.close();
+ }
+
+
+
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/crypt/DesUtil.java b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/DesUtil.java
new file mode 100644
index 0000000..b201a3d
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/DesUtil.java
@@ -0,0 +1,157 @@
+package com.mesalab.tool.crypt;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+
+/**
+ *
+ * <p>3des加密算法,针对消息进行加密的工具类 </p>
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2013-07-10
+ *
+ */
+public abstract class DesUtil {
+
+ /**
+ *
+ * <p>生成key</p>
+ * @return 返回密钥
+ */
+ public static SecretKey generateKey(){
+ Security.addProvider(new com.sun.crypto.provider.SunJCE());
+ KeyGenerator keyGenerator=null;
+ try {
+ keyGenerator = KeyGenerator.getInstance("DESede");
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ return keyGenerator.generateKey();
+ }
+
+ /**
+ * <p>对信息通过3des进行加密</p>
+ * @param srcMsg 明文信息
+ * @param key 生成对称密钥
+ * @return 密文
+ */
+ public static String encrypt(String srcMsg,SecretKey key){
+ byte[] enc = null;
+ try {
+ Cipher cipher = Cipher.getInstance("DESede");
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ byte[] src = srcMsg.getBytes();
+
+ enc = cipher.doFinal(src);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return Base64Utils.encode(enc);
+ }
+ /**
+ * <p>对信息通过3des进行解密</p>
+ * @param encMsg 密文信息
+ * @param key 对称密钥
+ * @return 明文信息
+ */
+ public static String decrypt(String encMsg,SecretKey key){
+ byte[] dec = null;
+ try {
+ Cipher cipher = Cipher.getInstance("DESede");
+ cipher.init(Cipher.DECRYPT_MODE, key);
+ dec = cipher.doFinal(Base64Utils.decode(encMsg.toCharArray()));
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return new String(dec);
+ }
+
+ static class Base64Utils {
+
+ static private char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();
+ static private byte[] codes = new byte[256];
+ static {
+ for (int i = 0; i < 256; i++)
+ codes[i] = -1;
+ for (int i = 'A'; i <= 'Z'; i++)
+ codes[i] = (byte) (i - 'A');
+ for (int i = 'a'; i <= 'z'; i++)
+ codes[i] = (byte) (26 + i - 'a');
+ for (int i = '0'; i <= '9'; i++)
+ codes[i] = (byte) (52 + i - '0');
+ codes['+'] = 62;
+ codes['/'] = 63;
+ }
+
+ /**
+ * 将原始数据编码为base64编码
+ */
+ static public String encode(byte[] data) {
+ char[] out = new char[((data.length + 2) / 3) * 4];
+ for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {
+ boolean quad = false;
+ boolean trip = false;
+ int val = (0xFF & (int) data[i]);
+ val <<= 8;
+ if ((i + 1) < data.length) {
+ val |= (0xFF & (int) data[i + 1]);
+ trip = true;
+ }
+ val <<= 8;
+ if ((i + 2) < data.length) {
+ val |= (0xFF & (int) data[i + 2]);
+ quad = true;
+ }
+ out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
+ val >>= 6;
+ out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];
+ val >>= 6;
+ out[index + 1] = alphabet[val & 0x3F];
+ val >>= 6;
+ out[index + 0] = alphabet[val & 0x3F];
+ }
+
+ return new String(out);
+ }
+
+ /**
+ * 将base64编码的数据解码成原始数据
+ */
+ static public byte[] decode(char[] data) {
+ int len = ((data.length + 3) / 4) * 3;
+ if (data.length > 0 && data[data.length - 1] == '=')
+ --len;
+ if (data.length > 1 && data[data.length - 2] == '=')
+ --len;
+ byte[] out = new byte[len];
+ int shift = 0;
+ int accum = 0;
+ int index = 0;
+ for (int ix = 0; ix < data.length; ix++) {
+ int value = codes[data[ix] & 0xFF];
+ if (value >= 0) {
+ accum <<= 6;
+ shift += 6;
+ accum |= value;
+ if (shift >= 8) {
+ shift -= 8;
+ out[index++] = (byte) ((accum >> shift) & 0xff);
+ }
+ }
+ }
+ if (index != out.length)
+ throw new Error("miscalculated data length!");
+ return out;
+ }
+ }
+
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/crypt/Digests.java b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/Digests.java
new file mode 100644
index 0000000..662391a
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/Digests.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) 2005-2012 springside.org.cn
+ */
+package com.mesalab.tool.crypt;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+
+import com.mesalab.tool.exception.Exceptions;
+
+
+/**
+ * 支持SHA-1/MD5消息摘要的工具类.
+ *
+ * 返回ByteSource,可进一步被编码为Hex, Base64或UrlSafeBase64
+ *
+ * @author
+ */
+public class Digests {
+
+ private static final String SHA1 = "SHA-1";
+ private static final String MD5 = "MD5";
+
+ private static SecureRandom random = new SecureRandom();
+
+ /**
+ * 对输入字符串进行md5散列.
+ */
+ public static byte[] md5(byte[] input) {
+ return digest(input, MD5, null, 1);
+ }
+ public static byte[] md5(byte[] input, int iterations) {
+ return digest(input, MD5, null, iterations);
+ }
+
+ /**
+ * 对输入字符串进行sha1散列.
+ */
+ public static byte[] sha1(byte[] input) {
+ return digest(input, SHA1, null, 1);
+ }
+
+ public static byte[] sha1(byte[] input, byte[] salt) {
+ return digest(input, SHA1, salt, 1);
+ }
+
+ public static byte[] sha1(byte[] input, byte[] salt, int iterations) {
+ return digest(input, SHA1, salt, iterations);
+ }
+
+ /**
+ * 对字符串进行散列, 支持md5与sha1算法.
+ */
+ private static byte[] digest(byte[] input, String algorithm, byte[] salt, int iterations) {
+ try {
+ MessageDigest digest = MessageDigest.getInstance(algorithm);
+
+ if (salt != null) {
+ digest.update(salt);
+ }
+
+ byte[] result = digest.digest(input);
+
+ for (int i = 1; i < iterations; i++) {
+ digest.reset();
+ result = digest.digest(result);
+ }
+ return result;
+ } catch (GeneralSecurityException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+ /**
+ * 生成随机的Byte[]作为salt.
+ *
+ * @param numBytes byte数组的大小
+ */
+ public static byte[] generateSalt(int numBytes) {
+
+ if ( numBytes <= 0 ) {
+ throw new IllegalArgumentException("numBytes argument must be a positive integer (1 or larger)");
+ }
+ byte[] bytes = new byte[numBytes];
+ random.nextBytes(bytes);
+ return bytes;
+ }
+
+ /**
+ * 对文件进行md5散列.
+ */
+ public static byte[] md5(InputStream input) throws IOException {
+ return digest(input, MD5);
+ }
+
+ /**
+ * 对文件进行sha1散列.
+ */
+ public static byte[] sha1(InputStream input) throws IOException {
+ return digest(input, SHA1);
+ }
+
+ private static byte[] digest(InputStream input, String algorithm) throws IOException {
+ try {
+ MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
+ int bufferLength = 8 * 1024;
+ byte[] buffer = new byte[bufferLength];
+ int read = input.read(buffer, 0, bufferLength);
+
+ while (read > -1) {
+ messageDigest.update(buffer, 0, read);
+ read = input.read(buffer, 0, bufferLength);
+ }
+
+ return messageDigest.digest();
+ } catch (GeneralSecurityException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/crypt/RSACoder.java b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/RSACoder.java
new file mode 100644
index 0000000..2d0f4ae
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/RSACoder.java
@@ -0,0 +1,313 @@
+package com.mesalab.tool.crypt;
+
+
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+
+import org.apache.commons.codec.binary.Hex;
+
+/**
+ *
+ * <p>RSA非对称加密算法安全编码组件 </p>
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2013-07-10
+ *
+ */
+public abstract class RSACoder {
+ //非对称加密密钥算法
+ public static final String KEY_ALGORITHM="RSA";
+ //数字签名 签名/验证算法
+ public static final String SIGNATURE_ALGORRITHM="SHA1withRSA";
+ //公钥
+ private static final String PUBLIC_KEY="RSAPublicKey";
+ //私钥
+ private static final String PRIVATE_KEY="RSAPrivateKey";
+ //RSA密钥长度,默认为1024,密钥长度必须是64的倍数,范围在521~65526位之间
+ private static final int KEY_SIZE=512;
+ /**
+ * 私钥解密
+ * @param data 待解密数据
+ * @param key 私钥
+ * @return byte[] 解密数据
+ * @throws Exception
+ */
+ public static byte[] decryptByPrivateKey(byte[] data,byte[]key) throws Exception
+ {
+ //取得私钥
+ PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(key);
+ KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
+ //生成私钥
+ PrivateKey privateKey=keyFactory.generatePrivate(pkcs8KeySpec);
+ //对数据解密
+ Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
+ cipher.init(Cipher.DECRYPT_MODE, privateKey);
+ return cipher.doFinal(data);
+ }
+ /**
+ * 私钥解密
+ * @param data 待解密数据
+ * @param privateKey 私钥
+ * @return byte[] 解密数据
+ * @throws Exception
+ */
+ public static byte[] decryptByPrivateKey(byte[] data,String privateKey) throws Exception
+ {
+ return decryptByPrivateKey(data,getKey(privateKey));
+ }
+ /**
+ * 公钥解密
+ * @param data 待解密数据
+ * @param key 公钥
+ * @return byte[] 解密数据
+ * @throws Exception
+ */
+ public static byte[] decryptByPublicKey(byte[] data,byte[] key) throws Exception
+ {
+ //取得公钥
+ X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
+ KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
+ //生成公钥
+ PublicKey publicKey=keyFactory.generatePublic(x509KeySpec);
+ //对数据解密
+ Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
+ cipher.init(Cipher.DECRYPT_MODE, publicKey);
+ return cipher.doFinal(data);
+ }
+ /**
+ * 公钥解密
+ * @param data 待解密数据
+ * @param publicKey 公钥
+ * @return byte[] 解密数据
+ * @throws Exception
+ */
+ public static byte[] decryptByPublicKey(byte[] data,String publicKey) throws Exception
+ {
+ return decryptByPublicKey(data,getKey(publicKey));
+ }
+ /**
+ * 公钥加密
+ * @param data 待加密数据
+ * @param key 公钥
+ * @return byte[] 加密数据
+ * @throws Exception
+ */
+ public static byte[] encryptByPublicKey(byte[] data,byte[] key) throws Exception
+ {
+ //取得公钥
+ X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
+ KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
+ PublicKey publicKey=keyFactory.generatePublic(x509KeySpec);
+ //对数据加密
+ Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
+ cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+ return cipher.doFinal(data);
+ }
+ /**
+ * 公钥加密
+ * @param data 待加密数据
+ * @param publicKey 公钥
+ * @return byte[] 加密数据
+ * @throws Exception
+ */
+ public static byte[] encryptByPublicKey(byte[] data,String publicKey) throws Exception
+ {
+ return encryptByPublicKey(data,getKey(publicKey));
+ }
+ /**
+ * 私钥加密
+ * @param data 待加密数据
+ * @param key 私钥
+ * @return byte[] 加密数据
+ * @throws Exception
+ */
+ public static byte[] encryptByPrivateKey(byte[] data,byte[] key) throws Exception
+ {
+ //取得私钥
+ PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(key);
+ KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
+ //生成私钥
+ PrivateKey privateKey=keyFactory.generatePrivate(pkcs8KeySpec);
+ //对数据加密
+ Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
+ cipher.init(Cipher.ENCRYPT_MODE, privateKey);
+ return cipher.doFinal(data);
+ }
+ /**
+ * 私钥加密
+ * @param data 待加密数据
+ * @param key 私钥
+ * @return byte[] 加密数据
+ * @throws Exception
+ */
+ public static byte[] encryptByPrivateKey(byte[] data,String key) throws Exception
+ {
+ return encryptByPrivateKey(data,getKey(key));
+ }
+ /**
+ * 取得私钥
+ * @param keyMap 密钥Map
+ * @return byte[] 私钥
+ * @throws Exception
+ */
+ public static byte[] getPrivateKey(Map<String,Object> keyMap) throws Exception
+ {
+ Key key=(Key)keyMap.get(PRIVATE_KEY);
+ return key.getEncoded();
+ }
+ /**
+ * 取得公钥
+ * @param keyMap 密钥Map
+ * @return byte[] 公钥
+ * @throws Exception
+ */
+ public static byte[] getPublicKey(Map<String,Object> keyMap) throws Exception
+ {
+ Key key=(Key)keyMap.get(PUBLIC_KEY);
+ return key.getEncoded();
+ }
+ /**
+ * 初始化密钥
+ * @return 密钥Map
+ * @throws Exception
+ */
+ public static Map<String,Object> initKey() throws Exception
+ {
+ //实例化实钥对生成器
+ KeyPairGenerator keyPairGen=KeyPairGenerator.getInstance(KEY_ALGORITHM);
+ //初始化密钥对生成器
+ keyPairGen.initialize(KEY_SIZE);
+ //生成密钥对
+ KeyPair keyPair=keyPairGen.generateKeyPair();
+ //公钥
+ RSAPublicKey publicKey=(RSAPublicKey) keyPair.getPublic();
+ //私钥
+ RSAPrivateKey privateKey=(RSAPrivateKey) keyPair.getPrivate();
+ //封装密钥
+ Map<String,Object> keyMap=new HashMap<String,Object>(2);
+ keyMap.put(PUBLIC_KEY, publicKey);
+ keyMap.put(PRIVATE_KEY, privateKey);
+ return keyMap;
+ }
+ /**
+ * 签名
+ * @param data 待签名数据
+ * @param privateKey 私钥
+ * @return byte[] 数字签名
+ * @throws Exception
+ */
+ public static byte[] sign(byte[] data,byte[] privateKey) throws Exception
+ {
+ //转接私钥材料
+ PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(privateKey);
+ //实例化密钥工厂
+ KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
+ //取私钥对象
+ PrivateKey priKey=keyFactory.generatePrivate(pkcs8KeySpec);
+ //实例化Signature
+ Signature signature=Signature.getInstance(SIGNATURE_ALGORRITHM);
+ //初始化Signature
+ signature.initSign(priKey);
+ //更新
+ signature.update(data);
+ //签名
+ return signature.sign();
+ }
+ /**
+ * 公钥校验
+ * @param data 待校验数据
+ * @param publicKey 公钥
+ * @param sign 数字签名
+ * @return boolean 公钥校验
+ * @throws Exception
+ */
+ public static boolean verify(byte[] data,byte[] publicKey,byte[] sign) throws Exception
+ {
+ //转接公钥材料
+ X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(publicKey);
+ //实例化密钥工厂
+ KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
+ //生成公钥
+ PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
+ //实例化Signature
+ Signature signature=Signature.getInstance(SIGNATURE_ALGORRITHM);
+ //初始化Signature
+ signature.initVerify(pubKey);
+ //更新
+ signature.update(data);
+ //验证
+ return signature.verify(sign);
+ }
+ /**
+ * 私钥签名
+ * @param data 待签名数据
+ * @param privateKey 私钥
+ * @return String 十六进制签名字符串
+ * @throws Exception
+ */
+ public static String sign(byte[] data,String privateKey) throws Exception
+ {
+ byte[] sign=sign(data,getKey(privateKey));
+
+ //Hex.encodeHexString(sign)
+ return new String(Hex.encodeHex(sign));
+ }
+ /**
+ * 公钥校验
+ * @param data 待验证数据
+ * @param publicKey 公钥
+ * @param sign 签名
+ * @return boolean 成功返回true,失败返回false
+ * @throws Exception
+ */
+ public static boolean verify(byte[] data,String publicKey,String sign) throws Exception
+ {
+ return verify(data,getKey(publicKey),Hex.decodeHex(sign.toCharArray()));
+ }
+
+ /**
+ * 取得私钥十六进制表示形式
+ * @param keyMap 密钥Map
+ * @return String 私钥十六进制字符串
+ * @throws Exception
+ */
+ public static String getPrivateKeyString(Map<String,Object> keyMap) throws Exception
+ {
+ //Hex.encodeHexString(getPrivateKey(keyMap))
+ return new String(Hex.encodeHex(getPrivateKey(keyMap))) ;
+ }
+ /**
+ * 取得公钥十六进制表示形式
+ * @param keyMap 密钥Map
+ * @return String 公钥十六进制字符串
+ * @throws Exception
+ */
+ public static String getPublicKeyString(Map<String,Object> keyMap) throws Exception
+ {
+ // Hex.encodeHexString(getPublicKey(keyMap))
+ return new String(Hex.encodeHex(getPublicKey(keyMap))) ;
+ }
+ /**
+ * 获取密钥
+ * @param key 密钥
+ * @return byte[] 密钥
+ * @throws Exception
+ */
+ public static byte[] getKey(String key) throws Exception
+ {
+ return Hex.decodeHex(key.toCharArray());
+ }
+}
+
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/crypt/package.html b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/package.html
new file mode 100644
index 0000000..84c081f
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/crypt/package.html
@@ -0,0 +1,58 @@
+<html>
+<body>
+<p>
+提供对数据加密、界面工具类.
+ 附证书生成命令:
+ keytool生成证书
+ keytool -genkeypair -keyalg RSA -keysize 2048 -sigalg SHA1withRSA -validity 360 -alias www.dominic.com -keystore dominic.keystore
+ 导出数字证书
+ keytool -exportcert -alias www.dominic.com -keystore dominic.keystore -file dominic.cer -rfc
+ 打印数字证书
+ keytool -printcert -file dominic.cer
+ 这里是自制证书,如果需要权威机构签发,需要导出证书申请文件由第三方签发
+
+ openssl证书创建
+
+ 根证书构建命令?
+ echo 构建随机数 private/.rand
+ openssl rand -out private/.rand 1000
+ echo 构建根证书私钥 private/ca.key.pem
+ openssl genrsa -aes256 -out private/ca.key.pem 2048
+ echo 生成根证书签发申请 private/ca.csr
+ openssl req -new -key private/ca.key.pem -out private/ca.csr -subj "/C=CN/ST=BJ/L=BJ/O=dominic/OU=dominic/CN=www.dominic.com"
+ echo 签发根证书 private/ca.cer
+ openssl x509 -req -days 10000 -sha1 -extensions v3_ca -signkey private/ca.key.pem -in private/ca.csr -out certs/ca.cer
+ echo 根证书转换 private/ca.p12
+ openssl pkcs12 -export -cacerts inkey private/ca.key.pem -in private/ca.csr -out certs/ca.cer
+
+ 服务器证书构建步骤命令?
+ (1)echo 构建服务器私钥 private/server.key.pem
+ (2)openssl genrsa -aes256 -out private/server.key.pem 2048
+ echo 生成服务器证书签发申请 private/server.csr
+ (3)openssl req -new -key private/server.key.pem -out private/server.csr -subj "/C=CN/ST=BJ/L=BJ/O=dominic/OU=dominic/CN=www.dominic.com"
+ echo 签发服务器证书 private/server.cer
+ openssl x509 -req -days 3650 -sha1 -extensions v3_req -CA certs/ca.cer -CAkey private/ca.key.pem -CAserial ca.srl -CAcreateserial -in private/server.csr -out certs/server.cer
+ echo 服务器证书转换 private/server.p12
+ openssl pkcs12 -export -clcerts -inkey private/server.key.pem -in certs/server.cer -out certs/server.p12
+
+ 客户证书构建命令?
+ echo 构建客户私钥 private/client.key.pem
+ openssl genrsa -aes256 -out private/client.key.pem 2048
+ echo 生成服务器证书签发申请 private/client.csr
+ openssl req -new -key private/client.key.pem -out private/client.csr -subj "/C=CN/ST=BJ/L=BJ/O=dominic/OU=dominic/CN=www.dominic.com"
+ echo 签发客户证书 private/server.cer
+ openssl ca -days 3650 -in private/client.csr -out certs/client.cer -cert certs/ca.cer -keyfile private/ca.key.pem
+ echo 客户证书转换 certs/client.p12
+ openssl pkcs12 -export -inkey private/client.key.pem -in certs/client.cer -out certs/client.p12
+<p>
+包括:
+<ul>
+<li><code>AESUtil</code> - AES对称加密算法,组件类.</li>
+<li><code>DesFileUtil</code> - 3des加密算法,针对文件进行加密的工具类.</li>
+<li><code>DesUtil</code> - 3des加密算法,针对消息进行加密的工具类.</li>
+<li><code>RSACoder</code> - RSA非对称加密算法安全编码组件.</li>
+<li><code>CertificateCoder</code> - X.509证书组件.</li>
+</ul>
+@since 1.1
+</body>
+</html> \ No newline at end of file
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/domain/JsonInjector.java b/galaxy-tool/src/main/java/com/mesalab/tool/domain/JsonInjector.java
new file mode 100644
index 0000000..8ea08ef
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/domain/JsonInjector.java
@@ -0,0 +1,44 @@
+package com.mesalab.tool.domain;/**
+ * Created by dell on 2018-10-8.
+ */
+
+import com.fasterxml.jackson.databind.BeanProperty;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.InjectableValues;
+import com.maxmind.geoip2.record.Traits;
+
+import java.util.List;
+
+/**
+ * @ClassName JsonInjector
+ * @Description TODO
+ * @Author dell
+ * @Date 2018-10-8 18:38
+ * @Version 1.0
+ **/
+public class JsonInjector extends InjectableValues {
+
+ private final List<String> locales;
+ private final String ip;
+
+ public JsonInjector(List<String> locales, String ip) {
+ this.locales = locales;
+ this.ip = ip;
+ }
+
+ @Override
+ public Object findInjectableValue(Object valueId, DeserializationContext ctxt,
+ BeanProperty forProperty, Object beanInstance) {
+ if ("locales".equals(valueId)) {
+ return locales;
+ }
+ if ("ip_address".equals(valueId)) {
+ return ip;
+ }
+ if ("traits".equals(valueId)) {
+ return new Traits(ip);
+ }
+ return null;
+ }
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/domain/LocationResponse.java b/galaxy-tool/src/main/java/com/mesalab/tool/domain/LocationResponse.java
new file mode 100644
index 0000000..87cd83b
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/domain/LocationResponse.java
@@ -0,0 +1,142 @@
+package com.mesalab.tool.domain;/**
+ * Created by dell on 2018-10-8.
+ */
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+
+/**
+ * @ClassName CountryResponse
+ * @Description TODO
+ * @Author dell
+ * @Date 2018-10-8 18:56
+ * @Version 1.0
+ **/
+public class LocationResponse {
+
+ private String areaCode;
+
+ private String asn;
+
+ private String city;
+
+ private String country;
+
+ private String isp;
+
+ private String latitude;
+
+ private String longitude;
+
+ private String province;
+
+ private String organization;
+
+ private String countryCode;
+
+ public LocationResponse() {
+
+ this("", "", "", "", "", "", "", "", "", "");
+ }
+
+ public LocationResponse(@JsonProperty("AREA_CODE") String areaCode, @JsonProperty("ASN") String asn,
+ @JsonProperty("CITY") String city, @JsonProperty("COUNTRY") String country,
+ @JsonProperty("ISP") String isp, @JsonProperty("LATITUDE") String latitude,
+ @JsonProperty("LONGITUDE") String longitude, @JsonProperty("PROVINCE") String province,
+ @JsonProperty("ORGANIZATION") String organization, @JsonProperty("COUNTRY_CODE") String countryCode) {
+ this.areaCode = areaCode;
+ this.asn = asn;
+ this.city = city;
+ this.isp = isp;
+ this.latitude = latitude;
+ this.longitude = longitude;
+ this.province = province;
+ this.country = country;
+ this.organization = organization;
+ this.countryCode = countryCode;
+
+ }
+
+ public String getAreaCode() {
+ return areaCode;
+ }
+
+ public void setAreaCode(String areaCode) {
+ this.areaCode = areaCode;
+ }
+
+ public String getAsn() {
+ return asn;
+ }
+
+ public void setAsn(String asn) {
+ this.asn = asn;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+
+ public String getCountry() {
+ return country;
+ }
+
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public String getIsp() {
+ return isp;
+ }
+
+ public void setIsp(String isp) {
+ this.isp = isp;
+ }
+
+ public String getLatitude() {
+ return latitude;
+ }
+
+ public void setLatitude(String latitude) {
+ this.latitude = latitude;
+ }
+
+ public String getLongitude() {
+ return longitude;
+ }
+
+ public void setLongitude(String longitude) {
+ this.longitude = longitude;
+ }
+
+ public String getProvince() {
+ return province;
+ }
+
+ public void setProvince(String province) {
+ this.province = province;
+ }
+
+ public String getOrganization() {
+ return organization;
+ }
+
+ public void setOrganization(String organization) {
+ this.organization = organization;
+ }
+
+ public String getCountryCode() {
+ return countryCode;
+ }
+
+ public void setCountryCode(String countryCode) {
+ this.countryCode = countryCode;
+ }
+}
+
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/domain/Nets.java b/galaxy-tool/src/main/java/com/mesalab/tool/domain/Nets.java
new file mode 100644
index 0000000..608c5f0
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/domain/Nets.java
@@ -0,0 +1,31 @@
+package com.mesalab.tool.domain;
+
+/**
+ * Created by dell on 2018-8-30.
+ */
+public class Nets {
+
+ private String StartIP;
+ private String EndIP;
+ private String NetMask;
+ public String getStartIP() {
+ return StartIP;
+ }
+ public void setStartIP(String startIP) {
+ StartIP = startIP;
+ }
+ public String getEndIP() {
+ return EndIP;
+ }
+ public void setEndIP(String endIP) {
+ EndIP = endIP;
+ }
+ public String getNetMask() {
+ return NetMask;
+ }
+ public void setNetMask(String netMask) {
+ NetMask = netMask;
+ }
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/exception/Exceptions.java b/galaxy-tool/src/main/java/com/mesalab/tool/exception/Exceptions.java
new file mode 100644
index 0000000..967312a
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/exception/Exceptions.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2005-2012 springside.org.cn
+ */
+package com.mesalab.tool.exception;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+
+/**
+ * 关于异常的工具类.
+ * @author
+ * @version
+ */
+public class Exceptions {
+
+ /**
+ * 将CheckedException转换为UncheckedException.
+ */
+ public static RuntimeException unchecked(Exception e) {
+ if (e instanceof RuntimeException) {
+ return (RuntimeException) e;
+ } else {
+ return new RuntimeException(e);
+ }
+ }
+
+ /**
+ * 将ErrorStack转化为String.
+ */
+ public static String getStackTraceAsString(Throwable e) {
+ if (e == null){
+ return "";
+ }
+ StringWriter stringWriter = new StringWriter();
+ e.printStackTrace(new PrintWriter(stringWriter));
+ return stringWriter.toString();
+ }
+
+ /**
+ * 判断异常是否由某些底层的异常引起.
+ */
+ public static boolean isCausedBy(Exception ex, Class<? extends Exception>... causeExceptionClasses) {
+ Throwable cause = ex.getCause();
+ while (cause != null) {
+ for (Class<? extends Exception> causeClass : causeExceptionClasses) {
+ if (causeClass.isInstance(cause)) {
+ return true;
+ }
+ }
+ cause = cause.getCause();
+ }
+ return false;
+ }
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/file/FileApplication.java b/galaxy-tool/src/main/java/com/mesalab/tool/file/FileApplication.java
new file mode 100644
index 0000000..4f13169
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/file/FileApplication.java
@@ -0,0 +1,631 @@
+package com.mesalab.tool.file;
+
+import com.mesalab.tool.utils.DateUtils;
+import com.mesalab.tool.utils.StringUtil;
+import com.mesalab.tool.utils.TimeConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+
+/**
+ *
+ * <p>该类提供对文件的基本及其路径的处理</p>
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2011-05-31 下午13:28:28
+ *
+ */
+public final class FileApplication extends org.apache.commons.io.FileUtils {
+
+ private static Logger logger = LoggerFactory.getLogger(FileApplication.class);
+
+ private static final FileApplication fileApplication = new FileApplication();
+
+ /**
+ *
+ * <p>过滤掉文件名的特殊字符</p>
+ * <pre>
+ * 文件名如带有 xiao\xin.txt = xiao xin.txt
+ * xiao/xin.txt = xiao xin.txt
+ * </pre>
+ * @param fileName 文件名称
+ * @return 返回过滤后文件名称
+ */
+ public static String filterFileName(String fileName){
+ return fileName.replaceAll("[ \\\\|/|\\? ]+"," ");
+ }
+
+ /**
+ *
+ * <p>判断文件或目录是否存在</p>
+ * @param path 文件或目录的路径
+ * @return true or false 文件或目录存在返回<code>true</code>,否则返回<code>false</code>.
+ */
+ public static boolean isExist(String path){
+ File file = new File(path);
+ return file.exists();
+ }
+
+
+ /**
+ *
+ * <p>判断文件是否存在</p>
+ * @param file 文件的路径
+ * @return <code>true</code> 文件存在,<code>false</code>不是文件或文件不存在.
+ */
+ public static boolean fileIsExist(File file){
+ return file.isFile() && file.exists();
+ }
+
+
+ /**
+ *
+ * <p>给定文件名获取唯一文件名称
+ * 例如:aa.txt 返回结果aa_20120531101233.txt
+ * </p>
+ * @param fileName 文件名称
+ * @return 唯一文件名称
+ */
+ public static String getOnlyFileName(String fileName){
+
+ String extendName = getFileExtendName(fileName);
+ if(StringUtil.isBlank(fileName)){
+ extendName="";
+ fileName = fileName+"_"+ DateUtils.getCurrentDate(TimeConstants.YYYYMMDDHH24MMSS);
+ }else {
+ extendName = extendName.toLowerCase();
+ fileName = fileName.substring(0,fileName.indexOf(extendName)-1)+"_"+DateUtils.getCurrentDate(TimeConstants.YYYYMMDDHH24MMSS)
+ +"."+extendName;
+ }
+
+ return fileName;
+ }
+
+ /**
+ *
+ * <p>
+ * 获得文件扩展名
+ * TXT,HTML,HTM,EML,DOC,DOCX,XLS,XLSX,PPT,PPTX,PDF
+ * </p>
+ * @param filePath 文件路径
+ * @return <code>string</code> 扩展名 ,<code>null</code> 时无扩展名
+ */
+ public static String getFileExtendName(String filePath) {
+ String extendName = null;
+ if(filePath.lastIndexOf(".") != -1){
+ extendName = filePath.substring(filePath.lastIndexOf(".")+1).trim().toUpperCase();
+ }
+ return extendName;
+ }
+
+
+
+ /**
+ * 创建单个文件
+ *
+ * @param descFileName
+ * 文件名,包含路径
+ * @return 如果创建成功,则返回true,否则返回false
+ */
+ public static boolean createFile(String descFileName) {
+ File file = new File(descFileName);
+ if (file.exists()) {
+ logger.debug("文件 " + descFileName + " 已存在!");
+ return false;
+ }
+ if (descFileName.endsWith(File.separator)) {
+ logger.debug(descFileName + " 为目录,不能创建目录!");
+ return false;
+ }
+ if (!file.getParentFile().exists()) {
+ // 如果文件所在的目录不存在,则创建目录
+ if (!file.getParentFile().mkdirs()) {
+ logger.debug("创建文件所在的目录失败!");
+ return false;
+ }
+ }
+
+ // 创建文件
+ try {
+ if (file.createNewFile()) {
+ logger.debug(descFileName + " 文件创建成功!");
+ return true;
+ } else {
+ logger.debug(descFileName + " 文件创建失败!");
+ return false;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ logger.debug(descFileName + " 文件创建失败!");
+ return false;
+ }
+
+ }
+
+ /**
+ * 创建目录
+ *
+ * @param descDirName
+ * 目录名,包含路径
+ * @return 如果创建成功,则返回true,否则返回false
+ */
+ public static boolean createDirectory(String descDirName) {
+ String descDirNames = descDirName;
+ if (!descDirNames.endsWith(File.separator)) {
+ descDirNames = descDirNames + File.separator;
+ }
+ File descDir = new File(descDirNames);
+ if (descDir.exists()) {
+ logger.debug("目录 " + descDirNames + " 已存在!");
+ return false;
+ }
+ // 创建目录
+ if (descDir.mkdirs()) {
+ logger.debug("目录 " + descDirNames + " 创建成功!");
+ return true;
+ } else {
+ logger.debug("目录 " + descDirNames + " 创建失败!");
+ return false;
+ }
+
+ }
+
+
+ /**
+ *
+ * 删除文件,可以删除单个文件或文件夹
+ *
+ * @param fileName
+ * 被删除的文件名
+ * @return 如果删除成功,则返回true,否是返回false
+ */
+ public static boolean delFile(String fileName) {
+ File file = new File(fileName);
+ if (!file.exists()) {
+ logger.debug(fileName + " 文件不存在!");
+ return true;
+ } else {
+ if (file.isFile()) {
+ return deleteFile(fileName);
+ } else {
+ return deleteDirectory(fileName);
+ }
+ }
+ }
+
+ /**
+ *
+ * 删除单个文件
+ *
+ * @param fileName
+ * 被删除的文件名
+ * @return 如果删除成功,则返回true,否则返回false
+ */
+ public static boolean deleteFile(String fileName) {
+ File file = new File(fileName);
+ if (file.exists() && file.isFile()) {
+ if (file.delete()) {
+ logger.debug("删除文件 " + fileName + " 成功!");
+ return true;
+ } else {
+ logger.debug("删除文件 " + fileName + " 失败!");
+ return false;
+ }
+ } else {
+ logger.debug(fileName + " 文件不存在!");
+ return true;
+ }
+ }
+
+ /**
+ *
+ * 删除目录及目录下的文件
+ *
+ * @param dirName
+ * 被删除的目录所在的文件路径
+ * @return 如果目录删除成功,则返回true,否则返回false
+ */
+ public static boolean deleteDirectory(String dirName) {
+ String dirNames = dirName;
+ if (!dirNames.endsWith(File.separator)) {
+ dirNames = dirNames + File.separator;
+ }
+ File dirFile = new File(dirNames);
+ if (!dirFile.exists() || !dirFile.isDirectory()) {
+ logger.debug(dirNames + " 目录不存在!");
+ return true;
+ }
+ boolean flag = true;
+ // 列出全部文件及子目录
+ File[] files = dirFile.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ // 删除子文件
+ if (files[i].isFile()) {
+ flag = deleteFile(files[i].getAbsolutePath());
+ // 如果删除文件失败,则退出循环
+ if (!flag) {
+ break;
+ }
+ }
+ // 删除子目录
+ else if (files[i].isDirectory()) {
+ flag = deleteDirectory(files[i].getAbsolutePath());
+ // 如果删除子目录失败,则退出循环
+ if (!flag) {
+ break;
+ }
+ }
+ }
+
+ if (!flag) {
+ logger.debug("删除目录失败!");
+ return false;
+ }
+ // 删除当前目录
+ if (dirFile.delete()) {
+ logger.debug("删除目录 " + dirName + " 成功!");
+ return true;
+ } else {
+ logger.debug("删除目录 " + dirName + " 失败!");
+ return false;
+ }
+
+ }
+
+ /**
+ * 写入文件
+ *
+ * @param fileName 要写入的文件
+ * @param content 内容
+ * @param append 是否追加 true or false
+ */
+ public static void writeToFile(String fileName, String content, boolean append) {
+ try {
+ write(new File(fileName), content, "utf-8", append);
+ logger.debug("文件 " + fileName + " 写入成功!");
+ } catch (IOException e) {
+ logger.debug("文件 " + fileName + " 写入失败! " + e.getMessage());
+ }
+ }
+
+ /**
+ * 写入文件
+ *
+ * @param fileName 要写入的文件
+ * @param content 内容
+ * @param encoding 编码
+ * @param append 是否追加 true or false
+ */
+ public static void writeToFile(String fileName, String content, String encoding, boolean append) {
+ try {
+ write(new File(fileName), content, encoding, append);
+ logger.debug("文件 " + fileName + " 写入成功!");
+ } catch (IOException e) {
+ logger.debug("文件 " + fileName + " 写入失败! " + e.getMessage());
+ }
+ }
+
+
+ /**
+ * 压缩文件或目录
+ *
+ * @param srcDirName
+ * 压缩的根目录
+ * @param fileName
+ * 根目录下的待压缩的文件名或文件夹名,其中*或""表示跟目录下的全部文件
+ * @param descFileName
+ * 目标zip文件
+ */
+ public static void zipFiles(String srcDirName, String fileName, String descFileName) {
+ // 判断目录是否存在
+ if (srcDirName == null) {
+ logger.debug("文件压缩失败,目录 " + srcDirName + " 不存在!");
+ return;
+ }
+ File fileDir = new File(srcDirName);
+ if (!fileDir.exists() || !fileDir.isDirectory()) {
+ logger.debug("文件压缩失败,目录 " + srcDirName + " 不存在!");
+ return;
+ }
+ String dirPath = fileDir.getAbsolutePath();
+ File descFile = new File(descFileName);
+ try {
+ ZipOutputStream zouts = new ZipOutputStream(new FileOutputStream(descFile));
+ if ("*".equals(fileName) || "".equals(fileName)) {
+ zipDirectoryToZipFile(dirPath, fileDir, zouts);
+ } else {
+ File file = new File(fileDir, fileName);
+ if (file.isFile()) {
+ zipFilesToZipFile(dirPath, file, zouts);
+ } else {
+ zipDirectoryToZipFile(dirPath, file, zouts);
+ }
+ }
+ zouts.close();
+ logger.debug(descFileName + " 文件压缩成功!");
+ } catch (Exception e) {
+ logger.debug("文件压缩失败:" + e.getMessage());
+ e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * 解压缩ZIP文件,将ZIP文件里的内容解压到descFileName目录下
+ *
+ * @param zipFileName
+ * 需要解压的ZIP文件
+ * @param descFileName
+ * 目标文件
+ */
+ public static boolean unZipFiles(String zipFileName, String descFileName) {
+ String descFileNames = descFileName;
+ if (!descFileNames.endsWith(File.separator)) {
+ descFileNames = descFileNames + File.separator;
+ }
+ try {
+ // 根据ZIP文件创建ZipFile对象
+ ZipFile zipFile = new ZipFile(zipFileName);
+ ZipEntry entry = null;
+ String entryName = null;
+ String descFileDir = null;
+ byte[] buf = new byte[4096];
+ int readByte = 0;
+ // 获取ZIP文件里所有的entry
+ @SuppressWarnings("rawtypes")
+ Enumeration enums = zipFile.entries();
+ // 遍历所有entry
+ while (enums.hasMoreElements()) {
+ entry = (ZipEntry) enums.nextElement();
+ // 获得entry的名字
+ entryName = entry.getName();
+ descFileDir = descFileNames + entryName;
+ if (entry.isDirectory()) {
+ // 如果entry是一个目录,则创建目录
+ new File(descFileDir).mkdirs();
+ continue;
+ } else {
+ // 如果entry是一个文件,则创建父目录
+ new File(descFileDir).getParentFile().mkdirs();
+ }
+ File file = new File(descFileDir);
+ // 打开文件输出流
+ OutputStream os = new FileOutputStream(file);
+ // 从ZipFile对象中打开entry的输入流
+ InputStream is = zipFile.getInputStream(entry);
+ while ((readByte = is.read(buf)) != -1) {
+ os.write(buf, 0, readByte);
+ }
+ os.close();
+ is.close();
+ }
+ zipFile.close();
+ logger.debug("文件解压成功!");
+ return true;
+ } catch (Exception e) {
+ logger.debug("文件解压失败:" + e.getMessage());
+ return false;
+ }
+ }
+
+ /**
+ * 将目录压缩到ZIP输出流
+ *
+ * @param dirPath
+ * 目录路径
+ * @param fileDir
+ * 文件信息
+ * @param zouts
+ * 输出流
+ */
+ public static void zipDirectoryToZipFile(String dirPath, File fileDir, ZipOutputStream zouts) {
+ if (fileDir.isDirectory()) {
+ File[] files = fileDir.listFiles();
+ // 空的文件夹
+ if (files.length == 0) {
+ // 目录信息
+ ZipEntry entry = new ZipEntry(getEntryName(dirPath, fileDir));
+ try {
+ zouts.putNextEntry(entry);
+ zouts.closeEntry();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return;
+ }
+
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isFile()) {
+ // 如果是文件,则调用文件压缩方法
+ zipFilesToZipFile(dirPath, files[i], zouts);
+ } else {
+ // 如果是目录,则递归调用
+ zipDirectoryToZipFile(dirPath, files[i], zouts);
+ }
+ }
+
+ }
+
+ }
+
+ /**
+ * 将文件压缩到ZIP输出流
+ *
+ * @param dirPath
+ * 目录路径
+ * @param file
+ * 文件
+ * @param zouts
+ * 输出流
+ */
+ public static void zipFilesToZipFile(String dirPath, File file, ZipOutputStream zouts) {
+ FileInputStream fin = null;
+ ZipEntry entry = null;
+ // 创建复制缓冲区
+ byte[] buf = new byte[4096];
+ int readByte = 0;
+ if (file.isFile()) {
+ try {
+ // 创建一个文件输入流
+ fin = new FileInputStream(file);
+ // 创建一个ZipEntry
+ entry = new ZipEntry(getEntryName(dirPath, file));
+ // 存储信息到压缩文件
+ zouts.putNextEntry(entry);
+ // 复制字节到压缩文件
+ while ((readByte = fin.read(buf)) != -1) {
+ zouts.write(buf, 0, readByte);
+ }
+ zouts.closeEntry();
+ fin.close();
+ System.out.println("添加文件 " + file.getAbsolutePath() + " 到zip文件中!");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ }
+
+
+ /**
+ * 获取待压缩文件在ZIP文件中entry的名字,即相对于跟目录的相对路径名
+ *
+ * @param dirPath
+ * 目录名
+ * @param file
+ * entry文件名
+ * @return
+ */
+ private static String getEntryName(String dirPath, File file) {
+ String dirPaths = dirPath;
+ if (!dirPaths.endsWith(File.separator)) {
+ dirPaths = dirPaths + File.separator;
+ }
+ String filePath = file.getAbsolutePath();
+ // 对于目录,必须在entry名字后面加上"/",表示它将以目录项存储
+ if (file.isDirectory()) {
+ filePath += "/";
+ }
+ int index = filePath.indexOf(dirPaths);
+
+ return filePath.substring(index + dirPaths.length());
+ }
+
+
+ /**
+ * 修复路径,将 \\ 或 / 等替换为 File.separator
+ *
+ * @param path
+ * @return
+ */
+ public static String path(String path) {
+ String p = StringUtil.replace(path, "\\", "/");
+ // p = StringUtils.join(StringUtils.split(p, "/"), "/");
+ if (!StringUtil.startsWithAny(p, "/") && StringUtil.startsWithAny(path, "\\", "/")) {
+ p += "/";
+ }
+ if (!StringUtil.endsWithAny(p, "/") && StringUtil.endsWithAny(path, "\\", "/")) {
+ p = p + "/";
+ }
+ return p;
+ }
+
+
+
+ /**
+ *
+ *<p>上传文件.</p>
+ * @param srcFile
+ * @param dirPath
+ * @param bufferSize
+ */
+ public static void upload(File srcFile, String dirPath, int bufferSize) throws FileNotFoundException{
+ try {
+
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ in = new BufferedInputStream(new FileInputStream(srcFile), bufferSize);
+ out = new BufferedOutputStream(new FileOutputStream(new File(dirPath)), bufferSize);
+ byte[] buffer = new byte[bufferSize];
+
+
+ int length = -1;
+ while((length = in.read(buffer)) != -1)
+ {
+ out.write(buffer, 0, length);
+ }
+
+
+ out.flush();
+ } finally {
+ if (null != in) {
+ in.close();
+ }
+ if (null != out) {
+ out.close();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("上传文件时出错!!!");
+ }
+ }
+
+ /**
+ * 获取文件唯一名称
+ *
+ * @return
+ */
+ public static String getFileKey() {
+ String suffixName = DateUtils.getCurrentDate("hhmmss");
+ return StringUtil.createUUID() + suffixName;
+
+ }
+
+
+ /**
+ * 获取文件后缀
+ *
+ * @param filename
+ * @param isDot
+ * true:加“.”
+ * @return
+ */
+ public static String getSuffix(String filename, Boolean isDot) {
+ String suffix = "";
+ int pos = filename.lastIndexOf('.');
+ if (pos > 0 && pos < filename.length() - 1) {
+ if (!isDot) {
+ pos = pos + 1;
+ }
+ suffix = filename.substring(pos);
+ }
+ return suffix;
+ }
+
+
+ /**
+ *
+ * <p>改变文件使其具有写属性.避免文件权限为只读操作.</p>
+ * @param fileName 文件或目录路径
+ * @return <code>true</code> 设置文件可写,<code>false</code> 文件不存在或已经具有写属性权限.
+ */
+ public static boolean setFileWritable(String fileName) {
+
+ File file = new File(fileName);
+
+ if (file.exists() && file.canRead() && !file.canWrite()) {
+ return file.setWritable(true);
+ }else {
+ return false;
+ }
+ }
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/file/FileFilterExtension.java b/galaxy-tool/src/main/java/com/mesalab/tool/file/FileFilterExtension.java
new file mode 100644
index 0000000..93f07e5
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/file/FileFilterExtension.java
@@ -0,0 +1,84 @@
+package com.mesalab.tool.file;
+
+import java.io.File;
+import java.io.FileFilter;
+
+
+/**
+ *
+ * <p>扩展文件过滤</p>
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2010-11-8 下午04:55:54
+ *
+ */
+public class FileFilterExtension implements FileFilter {
+
+ /**
+ * 是否接受目录
+ */
+ private boolean acceptDir;
+
+ /**
+ * 扩展名
+ */
+ private String fileType;
+ /**
+ * 文件名开始字符
+ */
+ private String fileNamePattern;
+
+ /**
+ *
+ *<p>Title:扩展过滤文件构造方法 </p>
+ *<p>Description: 构建对象</p>
+ *@param acceptDir 是否过滤目录 true or false
+ *@param fileNamePattern 文件名
+ *@param fileType 文件类型就是文件的扩展名
+ */
+
+ public FileFilterExtension(boolean acceptDir, String fileNamePattern, String fileType) {
+ this.acceptDir = acceptDir;
+ this.fileNamePattern = fileNamePattern;
+ this.fileType = fileType;
+ }
+
+ @Override
+ public boolean accept(File pathname) {
+
+ if (pathname.isDirectory() && !acceptDir) {
+ return false;
+ }
+
+ String name = pathname.getName();
+
+ int idx = name.lastIndexOf(".");
+
+ if (fileNamePattern != null) {
+ if (!name.startsWith(fileNamePattern)) {
+ return false;
+ }
+ }
+
+ if (fileType != null) {
+
+ if (idx == -1) {
+ return false;
+ } else{
+ if (idx == name.length() - 1) {
+ return false;
+ } else {
+ if (!this.fileType.equals(name.substring(idx + 1))) {
+ return false;
+ }
+ }
+ }
+
+
+ }
+
+ return true;
+ }
+
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/AbstractIpLookup.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/AbstractIpLookup.java
new file mode 100644
index 0000000..f898f87
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/AbstractIpLookup.java
@@ -0,0 +1,102 @@
+package com.mesalab.tool.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @ClassName AbstractIpLookup
+ * @Description 对IP定位查找抽象类,规定可执行方法
+ * @Author darnell
+ * @Date 2018-10-9 19:20
+ * @Version 1.0
+ **/
+public abstract class AbstractIpLookup {
+ protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+ protected static final String UNKNOW = "Unknown";
+ /**
+ * 给定IP库文件路径,获取国家代码
+ * @param ip ip地址
+ * @return String 国家代码
+ */
+ public abstract String countryLookup(String ip);
+
+ /**
+ *
+ * 获取详细定位信息
+ *
+ * @param ip ip地址,点分十进制格式,ipv4
+ * @return String 城市代码,省代码,国家代码
+ */
+ public abstract String cityLookupDetail(String ip);
+
+
+ /**
+ *
+ * 获取城市信息
+ *
+ * @param ip ip地址
+ * @return String 城市代码
+ */
+ public abstract String cityLookup(String ip);
+
+ /**
+ *
+ * 获取所属省信息
+ *
+ * @param ip ip地址
+ * @return String 州/省代码
+ */
+ public abstract String provinceLookup(String ip);
+
+
+ /**
+ *
+ * 获取经纬度信息
+ *
+ * @param ip ip地址
+ * @return String 纬度 经度
+ */
+ public abstract String latLngLookup(String ip);
+
+
+
+ /**
+ *
+ * 获城市与经纬度信息
+ *
+ * @param ip ip地址
+ * @return String 省代码 纬度 经度
+ */
+ public abstract String cityLatLngLookup(String ip);
+
+
+ /**
+ *
+ * 获取AS号,默认通过IP定位库获取ASN号
+ * @param ip ip地址
+ * @return String asn号
+ */
+ public abstract String asnLookup(String ip);
+
+ /**
+ *
+ * 获取IP 所属AS的组织+国家代码
+ * @param ip ip地址
+ * @return String asn号
+ */
+ public abstract String asnLookupInfo(String ip);
+
+
+
+ /**
+ *
+ * 获取AS号与组织信息
+ * @param ip ip地址
+ * @return asn号 组织名称
+ */
+ public abstract String asnLookupDetail(String ip);
+
+
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/AsnLookup.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/AsnLookup.java
new file mode 100644
index 0000000..0b0c8e1
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/AsnLookup.java
@@ -0,0 +1,473 @@
+package com.mesalab.tool.utils;
+
+import com.maxmind.db.CHMCache;
+import com.maxmind.geoip2.exception.AddressNotFoundException;
+import com.mesalab.tool.domain.LocationResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URL;
+
+/**
+ * @ClassName AsnLookup
+ * @Description IP查询AS号
+ * @Author 中电积至有限公司 darnell
+ * @Date 2020-05-09 13:45
+ * @Version 1.0.3
+ **/
+public class AsnLookup {
+ enum ServiceEnum {
+ PRIVATE, PUBLIC
+ }
+ protected static final String UNKNOW = "N/A";
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+ public final static String DEFAULT_DATABASE_PATH = "dat";
+ private final static String DEFAULT_DB_ASN_PUBLIC = "asn.mmdb";
+ private final static String DEFAULT_DB_ASN_PUBLIC_V4 = "asn_v4_201901.mmdb";
+ private final static String DEFAULT_DB_ASN_PUBLIC_V6 = "asn_v6_201901.mmdb";
+ private final static String DEFAULT_DB_ASN_PRIVATE = "asn_private.mmdb";
+ private final static String DEFAULT_DB_ASN_PRIVATE_V4 = "asn_private_v4.mmdb";
+ private final static String DEFAULT_DB_ASN_PRIVATE_V6 = "asn_private_v6.mmdb";
+
+
+ private static GalaxyDataBaseReader asnLocationPublicReader;
+ private static GalaxyDataBaseReader asnLocationPublicReaderV4;
+ private static GalaxyDataBaseReader asnLocationPublicReaderV6;
+
+ private static GalaxyDataBaseReader asnLocationPrivateReader;
+ private static GalaxyDataBaseReader asnLocationPrivateReaderV4;
+ private static GalaxyDataBaseReader asnLocationPrivateReaderV6;
+
+
+ synchronized void init(AsnLookup.Builder builder) {
+ try {
+
+ if (builder.isDefaultDB) {
+
+ File asnDbPublicFile = new File(System.getProperty("user.dir") + File.separator + DEFAULT_DATABASE_PATH + File.separator
+ + DEFAULT_DB_ASN_PUBLIC);
+ if (!asnDbPublicFile.exists()) {
+ URL url = IpLookup.class.getResource("/"+ DEFAULT_DATABASE_PATH + "/" + DEFAULT_DB_ASN_PUBLIC);
+ if (url != null) {
+ asnDbPublicFile = new File(url.getPath());
+ }
+
+ }
+
+
+ File asnDbPublicV4File = new File(System.getProperty("user.dir") + File.separator + DEFAULT_DATABASE_PATH + File.separator
+ + DEFAULT_DB_ASN_PUBLIC_V4);
+ if (!asnDbPublicV4File.exists()) {
+ URL url = IpLookup.class.getResource("/"+ DEFAULT_DATABASE_PATH + "/" + DEFAULT_DB_ASN_PUBLIC_V4);
+ if (url != null) {
+ asnDbPublicV4File = new File(url.getPath());
+ }
+
+ }
+
+ File asnDbPublicV6File = new File(System.getProperty("user.dir") + File.separator + DEFAULT_DATABASE_PATH + File.separator
+ + DEFAULT_DB_ASN_PUBLIC_V6);
+ if (!asnDbPublicV6File.exists()) {
+ URL url = IpLookup.class.getResource("/"+ DEFAULT_DATABASE_PATH + "/" + DEFAULT_DB_ASN_PUBLIC_V6);
+ if (url != null) {
+ asnDbPublicV6File = new File(url.getPath());
+ }
+ }
+
+ File asnDbPrivateFile = new File(System.getProperty("user.dir") + File.separator + DEFAULT_DATABASE_PATH + File.separator
+ + DEFAULT_DB_ASN_PRIVATE);
+ if (!asnDbPrivateFile.exists()) {
+ URL url = IpLookup.class.getResource("/"+ DEFAULT_DATABASE_PATH + "/" + DEFAULT_DB_ASN_PRIVATE);
+ if (url != null) {
+ asnDbPrivateFile = new File(url.getPath());
+ }
+
+ }
+
+ File asnDbPrivateV4File = new File(System.getProperty("user.dir") + File.separator + DEFAULT_DATABASE_PATH + File.separator
+ + DEFAULT_DB_ASN_PRIVATE_V4);
+ if (!asnDbPrivateV4File.exists()) {
+ URL url = IpLookup.class.getResource("/"+ DEFAULT_DATABASE_PATH + "/" + DEFAULT_DB_ASN_PRIVATE_V4);
+ if (url != null) {
+ asnDbPrivateV4File = new File(url.getPath());
+ }
+
+ }
+
+
+ File asnDbPrivateV6File = new File(System.getProperty("user.dir") + File.separator + DEFAULT_DATABASE_PATH + File.separator
+ + DEFAULT_DB_ASN_PRIVATE_V6);
+ if (!asnDbPrivateV6File.exists()) {
+ URL url = IpLookup.class.getResource("/"+ DEFAULT_DATABASE_PATH + "/" + DEFAULT_DB_ASN_PRIVATE_V6);
+ if (url != null) {
+ asnDbPrivateV6File = new File(url.getPath());
+ }
+ }
+
+ if (asnDbPublicFile.exists()) {
+ asnLocationPublicReader = new GalaxyDataBaseReader.Builder(asnDbPublicFile).withCache(new CHMCache()).build();
+ }
+ if (asnDbPublicV4File.exists()) {
+ asnLocationPublicReaderV4 = new GalaxyDataBaseReader.Builder(asnDbPublicV4File).withCache(new CHMCache()).build();
+ }
+
+ if (asnDbPublicV6File.exists()) {
+ asnLocationPublicReaderV6 = new GalaxyDataBaseReader.Builder(asnDbPublicV6File).withCache(new CHMCache()).build();
+ }
+ if (asnDbPrivateFile.exists()) {
+ asnLocationPrivateReader = new GalaxyDataBaseReader.Builder(asnDbPrivateFile).withCache(new CHMCache()).build();
+ }
+ if (asnDbPrivateV4File.exists()) {
+ asnLocationPrivateReaderV4 = new GalaxyDataBaseReader.Builder(asnDbPrivateV4File).withCache(new CHMCache()).build();
+ }
+
+ if (asnDbPrivateV6File.exists()) {
+ asnLocationPrivateReaderV6 = new GalaxyDataBaseReader.Builder(asnDbPrivateV6File).withCache(new CHMCache()).build();
+ }
+
+ } else {
+
+
+ if (StringUtil.isNotBlank(builder.asnDatabasePublicFile)) {
+ asnLocationPublicReader = new GalaxyDataBaseReader.Builder(new File(builder.asnDatabasePublicFile))
+ .withCache(new CHMCache()).build();
+ }
+ if (StringUtil.isNotBlank(builder.asnDatabasePublicFileV4)) {
+ asnLocationPublicReaderV4 = new GalaxyDataBaseReader.Builder(new File(builder.asnDatabasePublicFileV4))
+ .withCache(new CHMCache()).build();
+ }
+
+ if (StringUtil.isNotBlank(builder.asnDatabasePublicFileV6)) {
+ asnLocationPublicReaderV6 = new GalaxyDataBaseReader.Builder(new File(builder.asnDatabasePublicFileV6))
+ .withCache(new CHMCache()).build();
+ }
+
+ if (StringUtil.isNotBlank(builder.asnDatabasePrivateFile)) {
+ asnLocationPrivateReader = new GalaxyDataBaseReader.Builder(new File(builder.asnDatabasePrivateFile))
+ .withCache(new CHMCache()).build();
+ }
+
+ if (StringUtil.isNotBlank(builder.asnDatabasePrivateFileV4)) {
+ asnLocationPrivateReaderV4 = new GalaxyDataBaseReader.Builder(new File(builder.asnDatabasePrivateFileV4))
+ .withCache(new CHMCache()).build();
+ }
+
+ if (StringUtil.isNotBlank(builder.asnDatabasePrivateFileV6)) {
+ asnLocationPrivateReaderV6 = new GalaxyDataBaseReader.Builder(new File(builder.asnDatabasePrivateFileV6))
+ .withCache(new CHMCache()).build();
+ }
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ logger.warn("Unknow mmdb dat file , please check your dat path!");
+
+ }
+
+
+ }
+
+
+
+ private AsnLookup(AsnLookup.Builder builder) {
+ init(builder);
+ }
+
+
+ /**
+ * 加载mmdb数据字典文件,内部生成mmdb动态库。
+ *
+ * 1.默认记载ASN库,使用方式如下:
+ * AsnLookup asnLookup = new AsnLookup.Builder(true).build();
+ * 自动加载应用dat目录下的库文件,命名为:asn_v4.asn_v6.mmdb库。
+ *
+ * 2.手动加载IP库,使用方式如下:
+ * <p>
+ * AsnLookup asnLookup = new AsnLookup.Builder(false).loadDataFileV4("D:\\galaxy-tool\\dat\\asn_v4_201901.mmdb").
+ * loadDataFileV6("D:\\galaxy-tool\\dat\\asn_v6_201901.mmdb").build();
+ *
+ * </p>
+ */
+ public static final class Builder {
+ String asnDatabasePublicFile;
+ String asnDatabasePublicFileV4;
+ String asnDatabasePublicFileV6;
+ String asnDatabasePrivateFile;
+ String asnDatabasePrivateFileV4;
+ String asnDatabasePrivateFileV6;
+ boolean isDefaultDB;
+
+
+ /**
+ *
+ * @param isDefaultDB <code>false</code> 手动指定IP库路径 <code>true</code> 使用默认路径
+ */
+ public Builder(boolean isDefaultDB) {
+ this.isDefaultDB = isDefaultDB;
+ }
+
+ /**
+ *
+ * @param asnDatabasePublicFile 加载IPv4与IPv6 ASN库
+ * @return
+ */
+ public Builder loadDataFile(String asnDatabasePublicFile) {
+ this.asnDatabasePublicFile = asnDatabasePublicFile;
+ return this;
+ }
+
+ /**
+ *
+ * @param asnDatabasePublicFileV4 加载IPv4 ASN库
+ * @return
+ */
+ public Builder loadDataFileV4(String asnDatabasePublicFileV4) {
+ this.asnDatabasePublicFileV4 = asnDatabasePublicFileV4;
+ return this;
+ }
+
+ /**
+ *
+ * @param asnDatabasePublicFileV6 加载IPv6 ASN库
+ * @return
+ */
+ public Builder loadDataFileV6(String asnDatabasePublicFileV6) {
+ this.asnDatabasePublicFileV6 = asnDatabasePublicFileV6;
+ return this;
+ }
+
+ /**
+ *
+ * @param asnDatabasePrivateFile 加载IPv4与IPv6 用户自定义ASN库
+ * @return
+ */
+ public Builder loadDataFilePrivate(String asnDatabasePrivateFile) {
+ this.asnDatabasePrivateFile = asnDatabasePrivateFile;
+ return this;
+ }
+
+ /**
+ *
+ * @param asnDatabasePrivateFileV4 加载IPv4 用户自定义ASN库
+ * @return
+ */
+ public Builder loadDataFilePrivateV4(String asnDatabasePrivateFileV4) {
+ this.asnDatabasePrivateFileV4 = asnDatabasePrivateFileV4;
+ return this;
+ }
+
+ /**
+ *
+ * @param asnDatabasePrivateFileV6 加载IPv6 用户自定义ASN库
+ * @return
+ */
+ public Builder loadDataFilePrivateV6(String asnDatabasePrivateFileV6) {
+ this.asnDatabasePrivateFileV6 = asnDatabasePrivateFileV6;
+ return this;
+ }
+
+
+
+ /**
+ * 构建对象
+ * @return
+ * @throws IOException
+ */
+ public AsnLookup build() {
+ return new AsnLookup(this);
+ }
+
+
+
+ }
+
+
+
+ public String asnLookup(String ip) {
+ String result = UNKNOW;
+ LocationResponse response = getResponse(ip);
+
+
+ if (StringUtil.isNotEmpty(response)) {
+ result = StringUtil.isNotBlank(response.getAsn()) ? response.getAsn() : UNKNOW;
+ }
+
+ return result;
+
+ }
+
+ public String asnLookupInfo(String ip) {
+ String result = UNKNOW;
+ LocationResponse response = getResponse(ip);
+
+
+ if (StringUtil.isNotEmpty(response)) {
+ result = StringUtil.setDefaultIfEmpty(response.getOrganization(), UNKNOW)
+ +"," + StringUtil.setDefaultIfEmpty(response.getCountryCode(), UNKNOW);
+ }
+
+ return result;
+
+ }
+
+
+
+ public String asnLookupDetail(String ip) {
+ String result = UNKNOW;
+ LocationResponse response = getResponse(ip);
+
+ if (StringUtil.isNotEmpty(response)) {
+ result = StringUtil.setDefaultIfEmpty(response.getAsn(), UNKNOW) + "\t"
+ + StringUtil.setDefaultIfEmpty(response.getOrganization(), UNKNOW)
+ +"," + StringUtil.setDefaultIfEmpty(response.getCountryCode(), UNKNOW);
+ }
+
+
+ return result;
+ }
+
+
+
+
+ private LocationResponse getResponse(String ip) {
+ LocationResponse response = null;
+ if (!IPUtil.isIP(ip) && !IPUtil.isIPv6Address(ip)) {
+ throw new IllegalArgumentException("unknown ip format :" + ip );
+ }
+
+ response = new Context(new PrivateReader()).executeStragey(ip);
+
+ if (StringUtil.isEmpty(response)) {
+ response = new Context(new PublicReader()).executeStragey(ip);
+ }
+
+
+ return response;
+ }
+
+
+
+
+ private GalaxyDataBaseReader getAsnDataBaseReaderV4(String service) {
+ if (service.equalsIgnoreCase(ServiceEnum.PRIVATE.name())) {
+ if (StringUtil.isNotEmpty(asnLocationPrivateReaderV4)) {
+ return asnLocationPrivateReaderV4;
+ } else {
+ return asnLocationPrivateReader;
+ }
+ } else {
+ if (StringUtil.isNotEmpty(asnLocationPublicReaderV4)) {
+ return asnLocationPublicReaderV4;
+ } else{
+ return asnLocationPublicReader;
+ }
+ }
+ }
+
+ private GalaxyDataBaseReader getAsnDataBaseReaderV6(String service) {
+ if (service.equalsIgnoreCase(ServiceEnum.PRIVATE.name())) {
+ if (StringUtil.isNotEmpty(asnLocationPrivateReaderV6)) {
+ return asnLocationPrivateReaderV6;
+ } else {
+ return asnLocationPrivateReader;
+ }
+ } else {
+ if (StringUtil.isNotEmpty(asnLocationPublicReaderV6)) {
+ return asnLocationPublicReaderV6;
+ } else{
+ return asnLocationPublicReader;
+ }
+ }
+ }
+
+
+
+ interface Strategy {
+ LocationResponse getResponse(String ip);
+ }
+
+ /**
+ * 用户自定义IP库的执行策略
+ */
+ class PrivateReader implements Strategy {
+ @Override
+ public LocationResponse getResponse(String ip) {
+ GalaxyDataBaseReader dataBaseReader = null;
+ try {
+ InetAddress ipAddress = InetAddress.getByName(ip);
+
+ if (IPUtil.isIP(ip)) {
+ dataBaseReader = getAsnDataBaseReaderV4(ServiceEnum.PRIVATE.name());
+ } else if (IPUtil.isIPv6Address(ip)) {
+ dataBaseReader = getAsnDataBaseReaderV6(ServiceEnum.PRIVATE.name());
+ }
+
+ if (StringUtil.isNotEmpty(dataBaseReader)) {
+ return dataBaseReader.location(ipAddress);
+ }
+
+ } catch(AddressNotFoundException addressNotFoundException) {
+ logger.warn("Address not found ,ip is :" + ip);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("ip address :" + ip +", parser error " + e);
+ }
+ return null;
+ }
+ }
+ /**
+ * 第三方服务库的执行策略,例如maxmind、IPDAT
+ */
+ class PublicReader implements Strategy {
+ @Override
+ public LocationResponse getResponse(String ip) {
+ GalaxyDataBaseReader dataBaseReader = null;
+ try {
+ InetAddress ipAddress = InetAddress.getByName(ip);
+
+ if (IPUtil.isIP(ip)) {
+ dataBaseReader = getAsnDataBaseReaderV4(ServiceEnum.PUBLIC.name());
+
+ } else if (IPUtil.isIPv6Address(ip)) {
+ dataBaseReader = getAsnDataBaseReaderV6(ServiceEnum.PUBLIC.name());
+
+ }
+
+ if (StringUtil.isNotEmpty(dataBaseReader)) {
+ return dataBaseReader.location(ipAddress);
+ }
+
+ } catch(AddressNotFoundException addressNotFoundException) {
+ logger.warn("Address not found ,ip is :" + ip);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("ip address :" + ip +", parser error " + e);
+ }
+ return null;
+
+
+ }
+ }
+
+
+
+ class Context {
+ private Strategy strategy;
+
+ public Context(Strategy strategy) {
+ this.strategy = strategy;
+ }
+
+ public LocationResponse executeStragey(String ip) {
+ return strategy.getResponse(ip);
+ }
+
+ }
+
+
+
+
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/CIDRUtils.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/CIDRUtils.java
new file mode 100644
index 0000000..acd90c4
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/CIDRUtils.java
@@ -0,0 +1,138 @@
+package com.mesalab.tool.utils;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * <p>针对CIDR IP范围处理工具类.</p>
+ * @author 中电积至有限公司
+ * @version 1.0 创建时间:2020-04-21
+ *
+ */
+public class CIDRUtils {
+ private InetAddress inetAddress;
+ private InetAddress startAddress;
+ private InetAddress endAddress;
+ private final int prefixLength;
+ private final String cidr;
+
+ /**
+ * 参数示例:
+ * ipv4格式的cidr:221.178.125.0/24
+ * ipv6格式的cidr:2c0f:f7a8:9230::/48
+ *
+ * @param cidr
+ * @throws UnknownHostException
+ */
+ public CIDRUtils(String cidr) throws UnknownHostException {
+ this.cidr = cidr;
+ /* split CIDR to address and prefix part */
+ if (this.cidr.contains("/")) {
+ int index = this.cidr.indexOf("/");
+ String addressPart = this.cidr.substring(0, index);
+ String networkPart = this.cidr.substring(index + 1);
+ inetAddress = InetAddress.getByName(addressPart);
+ prefixLength = Integer.parseInt(networkPart);
+ calculate();
+ } else {
+ throw new IllegalArgumentException("not an valid CIDR format!");
+ }
+ }
+
+ public String getNetworkAddress() {
+ return this.startAddress.getHostAddress();
+ }
+
+
+ public BigInteger getNetworkAddressNum() {
+ return new BigInteger(1, this.startAddress.getAddress());
+ }
+
+
+ public String getBroadcastAddress() {
+ return this.endAddress.getHostAddress();
+ }
+
+ public BigInteger getBroadcastAddressNUm() {
+ return new BigInteger(1, this.endAddress.getAddress());
+ }
+
+ /**
+ * 判断ip是否在cidr里面
+ *
+ * @param ipAddress
+ * @return
+ * @throws UnknownHostException
+ */
+ public boolean isInRange(String ipAddress) throws UnknownHostException {
+ InetAddress address = InetAddress.getByName(ipAddress);
+ BigInteger start = new BigInteger(1, this.startAddress.getAddress());
+ BigInteger end = new BigInteger(1, this.endAddress.getAddress());
+ BigInteger target = new BigInteger(1, address.getAddress());
+ int st = start.compareTo(target);
+ int te = target.compareTo(end);
+
+ return (st == -1 || st == 0) && (te == -1 || te == 0);
+ }
+
+
+
+ private void calculate() throws UnknownHostException {
+ ByteBuffer maskBuffer;
+ int targetSize;
+ if (inetAddress.getAddress().length == 4) {
+ maskBuffer =
+ ByteBuffer
+ .allocate(4)
+ .putInt(-1);
+ targetSize = 4;
+ } else {
+ maskBuffer = ByteBuffer.allocate(16)
+ .putLong(-1L)
+ .putLong(-1L);
+ targetSize = 16;
+ }
+
+ BigInteger mask = (new BigInteger(1, maskBuffer.array())).not().shiftRight(prefixLength);
+ ByteBuffer buffer = ByteBuffer.wrap(inetAddress.getAddress());
+ BigInteger ipVal = new BigInteger(1, buffer.array());
+ BigInteger startIp = ipVal.and(mask);
+ BigInteger endIp = startIp.add(mask.not());
+ byte[] startIpArr = toBytes(startIp.toByteArray(), targetSize);
+ byte[] endIpArr = toBytes(endIp.toByteArray(), targetSize);
+ this.startAddress = InetAddress.getByAddress(startIpArr);
+ this.endAddress = InetAddress.getByAddress(endIpArr);
+ }
+
+
+
+
+
+
+ private static byte[] toBytes(byte[] array, int targetSize) {
+ int counter = 0;
+ List<Byte> newArr = new ArrayList<Byte>();
+ while (counter < targetSize && (array.length - 1 - counter >= 0)) {
+ newArr.add(0, array[array.length - 1 - counter]);
+ counter++;
+ }
+ int size = newArr.size();
+ for (int i = 0; i < (targetSize - size); i++) {
+ newArr.add(0, (byte) 0);
+ }
+ byte[] ret = new byte[newArr.size()];
+ for (int i = 0; i < newArr.size(); i++) {
+ ret[i] = newArr.get(i);
+ }
+ return ret;
+ }
+
+
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/CommonUtil.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/CommonUtil.java
new file mode 100644
index 0000000..779a087
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/CommonUtil.java
@@ -0,0 +1,246 @@
+package com.mesalab.tool.utils;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+
+
+
+/**
+ *
+ * <p>项目开发中常用公共类.通过类方法进行访问.</p>
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2010-11-8 下午04:50:04
+ *
+ */
+public final class CommonUtil {
+
+ private static final int ELEMENT_NOT_FOUND = -1;
+
+ /**
+ *<p>Description:抑制默认的构造器,避免实例化对象 </p>
+ */
+ private CommonUtil(){
+
+ }
+
+ /**
+ *
+ * <p>去掉List集合中重复的元素.如集合元素是实例对象,
+ * 需要重写{@link Object#equals(Object)}与{@link Object#hashCode()}方法.
+ * 注意:执行该方法后插入对象顺序将会打乱,执行效率高。如果想保持插入顺序可参看{@link #removeDuplicationWithOrder(List)}
+ * </p>
+ * <pre>
+ * List list &lt;Person&gt;,在去重之前一定要重写Person对象的{@link Object#equals(Object)}与 {@link Object#hashCode()}方法.
+ * List list = new ArrayList();
+ * list.add(10);
+ * list.add(11);
+ * list.add(10);
+ * removeDuplication(list);
+ * system.out.println(list.size());
+ * result:2
+ * </pre>
+ * @param list list集合
+ * @see #removeDuplicationWithOrder(List)
+ */
+ @SuppressWarnings("unchecked")
+ public static void removeDuplication(List<?> list){
+ if(StringUtil.isEmpty(list)){
+ throw new NullPointerException("List 集合对象为空");
+ }
+ Set set = new HashSet(list);
+ list.clear();
+ list.addAll(set);
+ }
+
+ /**
+ *
+ * <p>去掉List集合中重复的元素.如集合元素是实例对象,
+ * 需要重写{@link Object#equals(Object)}与{@link Object#hashCode()}方法.</p>
+ * 注意:该方法将保持list插入元素的顺序,但效率略差。效率高去重可采用{@link #removeDuplication(List)}
+ * <pre>
+ * List list &lt;Person&gt;,在去重之前一定要重写Person对象的{@link Object#equals(Object)}与 {@link Object#hashCode()}方法.
+ * </pre>
+ * @param list list集合
+ * @see #removeDuplication(List)
+ */
+ @SuppressWarnings("unchecked")
+ public static void removeDuplicationWithOrder(List<?> list){
+ if(StringUtil.isEmpty(list)){
+ throw new NullPointerException("List 集合对象为空");
+ }
+ Set<Object> set = new HashSet<Object>();
+ List newList = new ArrayList();
+ for (Iterator iter = list.iterator();iter.hasNext(); ) {
+ Object element = iter.next();
+ if (set.add(element)){
+ newList.add(element);
+ }
+ }
+ list.clear();
+ list.addAll(newList);
+ }
+
+ /**
+ *
+ * <p>精确小数位数,对一个浮点数按照给定的精度进行四舍五入.</p>
+ * <pre>
+ * double a1 = 1.789812302;
+ * CommonUtil.round(a1, 2) = 1.79
+ * CommonUtil.round(a1, 5) = 1.78981
+ *
+ * float a2 = 1.239f;
+ * CommonUtil.round(a1, 2) = 1.24
+ * CommonUtil.round(a1, 5) = 1.239
+ * </pre>
+ * @param value 处理值
+ * @param scale 精度(小数点后位数)
+ * @return double 返回四舍五入后的数值
+ * @throws IllegalArgumentException
+ */
+ public static double round(double value, int scale) {
+ return round(value, scale, BigDecimal.ROUND_HALF_UP);
+ }
+
+
+ /**
+ *
+ * <p>精确小数位数,对一个浮点数按照给定的精度取值,不进行四舍五入.</p>
+ * <pre>
+ * double a1 = 1.789812302;
+ * CommonUtil.roundPrecision(a1, 2) = 1.78
+ * CommonUtil.roundPrecision(a1, 5) = 1.78981
+ *
+ * float a2 = 1.239f;
+ * CommonUtil.roundPrecision(a1, 2) = 1.23
+ * CommonUtil.roundPrecision(a1, 5) = 1.239
+ * </pre>
+ * @param value 处理值
+ * @param scale 精度(小数点后位数)
+ * @return double 返回指定精度的数值
+ * @throws IllegalArgumentException
+ */
+ public static double roundPrecision(double value, int scale) {
+ return round(value, scale, BigDecimal.ROUND_FLOOR);
+ }
+
+ /**
+ *
+ * <p>精确小数位数,对一个浮点数按照给定的精度取值,不进行四舍五入.</p>
+ * @param value 处理值
+ * @param scale 精度(小数点后位数)
+ * @param mode 参见 {@link BigDecimal#ROUND_HALF_UP } 和 {@link BigDecimal#ROUND_FLOOR }用法
+ * @return double 返回指定精度的数值
+ * @throws IllegalArgumentException
+ */
+ public static double round(double value, int scale, int mode) {
+ if (scale < 0) {
+ throw new IllegalArgumentException(
+ "The scale must be a positive integer or zero");
+ }
+ BigDecimal b = new BigDecimal(Double.toString(value));
+ BigDecimal one = new BigDecimal("1");
+ return b.divide(one, scale, mode).doubleValue();
+ }
+
+ /**
+ *
+ * <p>将数组转存为集合方式,集合的接口为{@link Collection}.
+ * 注意数组如果为基本类型,需转换为包装类型.
+ * </p>
+ * <p>
+ * 在转换过程中,如果数组元素为空,将不存入集合中.
+ * </p>
+ * <pre>
+ * String[] aa = {"q","b",""};
+ * Integer[] bb = {1,4};
+ * List list = new ArrayList();
+ * CommonUtil.convertArrayToCollection(aa,list); = {"q","b"}
+ *
+ * Set set = new HashSet();
+ * CommonUtil.convertArrayToCollection(bb,set); = {1,4}
+ * </pre>
+ * @param <T>
+ * @param arrayValue 数组对象
+ * @param collection 集合对象
+ */
+ public static <T> void convertArrayToCollection(T[] arrayValue, Collection<T> collection){
+
+ if(StringUtil.isEmpty(arrayValue)){
+ return ;
+ }
+
+ for (T value : arrayValue) {
+
+ if(!StringUtil.isEmpty(value)){
+ collection.add(value);
+ }
+
+ }
+
+
+ }
+
+ /**
+ *
+ * <p>判断元素是否在数组中存在,存在返回<code>true</code>,否在返回<code>false</code></p>
+ * <pre>
+ * String[] aa = {"aa","nn","dd"};
+ * CommonUtil.existInArray(aa, "nn") = true
+ * CommonUtil.existInArray(aa, "ss") = false
+ * </pre>
+ * @param array 数组对象
+ * @param element 元素(判断是否存在数组中存在的对象元素)
+ * @return <code>true</code> 元素在数组中存在,<code>false</code> 元素在数组中不存在.
+ */
+
+ public static boolean existInArray(Object[] array ,Object element){
+
+
+ return indexOf(array,element)!=ELEMENT_NOT_FOUND;
+
+ }
+
+ /**
+ * 判断元素在数组中是否存在.存在返回非-1值,不存在返回-1.
+ */
+ private static int indexOf(Object[] array,Object element){
+
+ if(array==null){
+ return ELEMENT_NOT_FOUND;
+ }
+
+ if(element==null){
+ for( int i=0; i<array.length; i++ ){
+ if(array[i]==null){
+ return i;
+ }
+ }
+ }else {
+ for( int i=0; i<array.length; i++ ){
+ if(element.equals(array[i])){
+ return i;
+ }
+ }
+ }
+
+
+ return ELEMENT_NOT_FOUND;
+
+ }
+
+
+
+
+
+
+
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/CookieUtil.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/CookieUtil.java
new file mode 100644
index 0000000..677de0c
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/CookieUtil.java
@@ -0,0 +1,190 @@
+/*
+ * @(#)CookieUtil.java 1.0
+ *
+ * Copyright 2010 NIS, Inc. All rights reserved.
+ *
+ */
+package com.mesalab.tool.utils;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+
+
+/**
+ *
+ * <p>web 开发中用cookie管理工具类.</p>
+ * <p>
+ * 该工具类需有javaee.jar 包支持下才可使用.
+ * </p>
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2010-11-8 下午04:52:22
+ * @see javax.servlet.http.Cookie
+ *
+ */
+public final class CookieUtil extends Cookie {
+ /**
+ * 常量:一天的秒数
+ */
+ public static final int SECOND_PER_DAY= 60*60*24;
+
+ /**
+ * 常量:一周的秒数
+ */
+ public static final int SECOND_PER_WEEK=60*60*24*7;
+ /**
+ * 常量:一个月的秒数
+ */
+ public static final int SECOND_PER_MONTH=60*60*24*30;
+ /**
+ * 常量:一年的秒数
+ */
+ public static final int SECOND_PER_YEAR=60*60*24*365;
+
+ /**
+ * 常量:默认值为7天
+ */
+ public static final int DEFAULT_TIME=60*60*24*7;
+
+
+
+ /**
+ *<p>Title:Cookie 构造器 </p>
+ *<p>Description:实现Cookie类的构造器 </p>
+ *@param name Cookie 名称
+ *@param value Cookie名称所对应的值,必须为字符串类型
+ */
+ private CookieUtil(String name, String value) {
+ super(name, value);
+
+ }
+
+
+ /**
+ *
+ * <p>增加cookie,需要增加cookie保留状态</p>
+ * @param response http的{@link HttpServletResponse}响应头类
+ * @param name cookie 名称
+ * @param value Cookie名称所对应的值,必须为字符串类型
+ * @param state 通过web页面获取该值确定cookie失效时间
+ * @throws UnsupportedEncodingException 抛出设置编码不支持,默认设置编码为utf-8
+ */
+ public static void addCookie(HttpServletResponse response,String name,String value,String state) throws UnsupportedEncodingException{
+ value=URLEncoder.encode(value, "utf-8");
+ CookieUtil cookie = new CookieUtil(name,value);
+ if("year".equalsIgnoreCase(state)){
+ cookie.setMaxAge(SECOND_PER_YEAR);
+ } else if("month".equalsIgnoreCase(state)){
+ cookie.setMaxAge(SECOND_PER_MONTH);
+ } else if("week".equalsIgnoreCase(state)){
+ cookie.setMaxAge(SECOND_PER_WEEK);
+ }else if("day".equalsIgnoreCase(state)){
+ cookie.setMaxAge(SECOND_PER_DAY);
+ } else{
+ cookie.setMaxAge(DEFAULT_TIME);
+ }
+ //设置cookie 存放路径
+ cookie.setPath("/");
+ response.addCookie(cookie);
+
+ }
+
+ /**
+ *
+ * <p>增加cookie,需设置cookie失效时间值.</p>
+ * @param response http的{@link HttpServletResponse}响应头类.
+ * @param name cookie 名称.
+ * @param value Cookie名称所对应的值,必须为字符串类型
+ * @param time 失效时间值必须为整型,单位(秒).
+ * @throws UnsupportedEncodingException 抛出设置编码不支持,默认设置编码为utf-8
+ */
+ public static void addCookie(HttpServletResponse response,String name,String value,int time) throws UnsupportedEncodingException{
+ value=URLEncoder.encode(value,"utf-8");
+ CookieUtil cookie = new CookieUtil(name,value);
+ cookie.setMaxAge(time);
+ cookie.setPath("/");
+ response.addCookie(cookie);
+ }
+
+
+ /**
+ *
+ * <p>增加cookie,不设置失效状态或时间值默认为1周.</p>
+ * @param response http的{@link HttpServletResponse}响应头类
+ * @param name cookie 名称
+ * @param value Cookie名称所对应的值,必须为字符串类型
+ * @throws UnsupportedEncodingException 抛出设置编码不支持,默认设置编码为utf-8
+ */
+ public static void addCookie(HttpServletResponse response,String name,String value) throws UnsupportedEncodingException{
+ value=URLEncoder.encode(value,"utf-8");
+ CookieUtil cookie = new CookieUtil(name,value);
+ cookie.setMaxAge(DEFAULT_TIME);
+ cookie.setPath("/");
+ response.addCookie(cookie);
+ }
+
+ /**
+ *
+ * <p>删除cookie,将浏览器中保存的cookie通过name值找到并将该cookie设置失效时间为0.</p>
+ * @param request http的{@link HttpServletRequest} 请求头信息类.
+ * @param response http的{@link HttpServletResponse}响应头类.
+ * @param name cookie 名称
+ */
+ public static void deleteCookie(HttpServletRequest request,HttpServletResponse response,String name){
+ Cookie cookie=getCookie(request, name);
+ if(cookie!=null){
+ cookie.setMaxAge(0);
+ cookie.setPath("/");
+ response.addCookie(cookie);
+ }
+
+ }
+
+ private static Cookie getCookie(ServletRequest request,String cookiename){
+ HttpServletRequest req = (HttpServletRequest)request;
+ Cookie[] cookies = req.getCookies();
+
+ if(cookies!=null){
+ for(int i=0;i<cookies.length;i++){
+ if(cookies[i].getName().equals(cookiename)){
+
+ return cookies[i];
+ }
+
+ }
+ }
+
+
+ return null;
+ }
+
+ /**
+ * <p>根据Cookie 名称获取Cookie值</p>
+ * @param request http的{@link HttpServletRequest} 请求头信息类.
+ * @param cookiename cookie的名称,字符串类型.
+ * @return 返回cookie值
+ * @throws UnsupportedEncodingException 抛出设置编码不支持,默认设置编码为utf-8
+ */
+ public static String getValue(ServletRequest request,String cookiename) throws UnsupportedEncodingException{
+ HttpServletRequest req = (HttpServletRequest)request;
+ Cookie[] cookies = req.getCookies();
+
+ if(cookies!=null){
+ for(int i=0;i<cookies.length;i++){
+ if(cookies[i].getName().equals(cookiename)){
+
+ return URLDecoder.decode(cookies[i].getValue(), "utf-8");
+ }
+
+ }
+ }
+
+
+ return null;
+ }
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/DateUtil.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/DateUtil.java
new file mode 100644
index 0000000..66822fc
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/DateUtil.java
@@ -0,0 +1,470 @@
+package com.mesalab.tool.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+
+
+/**
+ *
+ * <p>时间/日期处理工具类</p>
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2010-11-8 下午04:48:57
+ * 该工具类较繁琐,功能单一并且有内存泄露及线程安全问题(SimpleDateFormat),日期处理请参见@see com.mesalab.tool.utils.DateUtils
+ */
+@Deprecated
+public final class DateUtil implements TimeConstants{
+
+ private static SimpleDateFormat simpleDateFormat = null;
+
+ /**
+ *<p>Description:抑制默认的构造器,避免实例化对象 </p>
+ */
+ private DateUtil() {
+
+ }
+
+
+
+
+
+ /**
+ *
+ * <p>获得当前日期,格式为默认yyyy-MM-dd.</p>
+ * <pre>
+ * DateUtil.getCurrentDate() = "2010-11-02"
+ * </pre>
+ * @see #getCurrentDate(String)
+ * @return String 返回标准日期格式(yyyy-MM-dd)
+ */
+ public static String getCurrentDate() {
+
+ simpleDateFormat = new SimpleDateFormat(YYYY_MM_DD);
+ return simpleDateFormat.format(new Date());
+ }
+
+ /**
+ *
+ * <p>
+ * 获得当前时间.
+ * 如果pattern为空,将抛出{@link NullPointerException}
+ * </p>
+ * <pre>
+ * DateUtil.getCurrentDate(TimeConstants.YYYY_MM_DD) = "2010-11-02"
+ * DateUtil.getCurrentDate("yyyy-MM-dd HH:mm:ss") = "2010-11-02 17:20:59"
+ * </pre>
+ * @param pattern 描述日期和时间格式.
+ * @return 当前日期
+ *
+ */
+ public static String getCurrentDate(String pattern) {
+
+ if(StringUtil.isEmpty(pattern)){
+ throw new NullPointerException("未规定时间格式.");
+ }
+ simpleDateFormat = new SimpleDateFormat(pattern);
+ return simpleDateFormat.format(new Date());
+ }
+
+ /**
+ *
+ * <p> 获得昨天时间.通过指定日期和时间格式,具体可参考本类提供的时间格式常量.</p>
+ * <pre>
+ * DateUtil.getDateOfYesterday(TimeConstants.YYYY_MM_DD_HH24_MM_SS) = "2010-11-04 16:59:13"
+ * </pre>
+ * @param pattern 描述日期和时间格式
+ * @see #getFormatDate(Date, String)
+ * @return String 返回日期的字符串表现形式值.
+ */
+ public static String getDateOfYesterday(String pattern) {
+
+ Calendar calendar = Calendar.getInstance();
+ calendar.add(Calendar.DAY_OF_MONTH, -1);
+ Date time = calendar.getTime();
+ return getFormatDate(time,pattern );
+
+ }
+
+ /**
+ *
+ * <p>
+ * 得到距离当天<code>offset</code>天数的某天日期,通过 <code>offset</code> 的值(+/-)来确定增减计算.
+ * </p>
+ * <pre>
+ * 当天日期: 2010-11-05
+ * DateUtil.getSomeDate("yyyy-MM-dd", 2) = 2010-11-07
+ * DateUtil.getSomeDate("yyyy-MM-dd", -2) = 2010-11-03
+ * DateUtil.getSomeDate("yyyy-MM-dd", 0) = 2010-11-05
+ * </pre>
+ * @param pattern 描述日期和时间格式
+ * @param offset 描述增加\减少几日,为0时为当前日期.
+ * @see #getFormatDate(Date, String)
+ * @return 返回日期格式的字符串
+ */
+
+ public static String getSomeDate(String pattern, int offset) {
+
+ Calendar calendar = Calendar.getInstance();
+ calendar.add(Calendar.DAY_OF_MONTH, offset);
+ Date time = calendar.getTime();
+
+ return getFormatDate(time,pattern);
+
+ }
+
+ /**
+ *
+ * <p>获得指定日期当月第一天</p>
+ * <pre>
+ * DateUtil.getFirstDayOfMonth(TimeConstants.YYYY_MM_DD_HH24_MM_SS, new Date()) = "2010-11-01 00:00:00"
+ * </pre>
+ * @param date 指定日期.
+ * @param pattern 描述日期和时间格式
+ * @return 返回日期格式的字符串
+ */
+ public static String getFirstDayOfMonth(Date date,
+ String pattern) {
+
+ if (StringUtil.isEmpty(pattern) || StringUtil.isEmpty(date)) {
+ throw new NullPointerException();
+ }
+
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(date);
+
+ Integer minDateNum = calendar.getActualMinimum(Calendar.DAY_OF_MONTH);
+
+ calendar.set(Calendar.DAY_OF_MONTH, minDateNum);
+ calendar.set(Calendar.HOUR, calendar.getActualMinimum(Calendar.HOUR));
+ calendar.set(Calendar.AM_PM, Calendar.AM);
+ calendar.set(Calendar.MINUTE, calendar
+ .getActualMinimum(Calendar.MINUTE));
+ calendar.set(Calendar.SECOND, calendar
+ .getActualMinimum(Calendar.SECOND));
+
+ return getFormatDate(calendar.getTime(), pattern );
+ }
+
+ /**
+ *
+ * <p>获得指定日期当月最后一天</p>
+ * <pre>
+ * DateUtil.getLastDayOfMonth(TimeConstants.YYYY_MM_DD_HH24_MM_SS, new Date()) = "2010-11-30 23:59:59"
+ * </pre>
+ * @param date 指定日期
+ * @param pattern 描述日期和时间格式
+ * @return 返回日期格式的字符串
+ */
+ public static String getLastDayOfMonth(Date date,
+ String pattern) {
+
+ if (StringUtil.isEmpty(pattern) || StringUtil.isEmpty(date)) {
+ throw new NullPointerException();
+ }
+
+ Calendar c = Calendar.getInstance();
+ c.setTime(date);
+ Integer maxDateNum = c.getActualMaximum(Calendar.DAY_OF_MONTH);
+ c.set(Calendar.DAY_OF_MONTH, maxDateNum);
+ c.set(Calendar.HOUR, c.getActualMaximum(Calendar.HOUR));
+ c.set(Calendar.AM_PM, Calendar.PM);
+ c.set(Calendar.MINUTE, c.getActualMaximum(Calendar.MINUTE));
+ c.set(Calendar.SECOND, c.getActualMaximum(Calendar.SECOND));
+ return getFormatDate(c.getTime(),pattern);
+ }
+
+ /**
+ *
+ * <p>获得指定日期的日.</p>
+ * @param date 日期值
+ * @return 返回日期的日.如果{@link java.util.Date}为<code>null</code>,抛出异常.
+ * @throws NullPointerException
+ */
+ public static String getDDFromDate(Date date) {
+ if (null==date) {
+ throw new NullPointerException("未存储日期对象");
+ }
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(date);
+
+ return calendar.get(Calendar.DATE)+"";
+
+ }
+
+ /**
+ *
+ * <p>获得指定日期的月.</p>
+ * @param date 指定日期
+ * @return 返回日期的月.如果{@link java.util.Date}为<code>null</code>,抛出异常.
+ * @throws NullPointerException
+ */
+ public static String getMMFromDate(Date date) {
+
+ if (null==date) {
+ throw new NullPointerException();
+ }
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(date);
+ calendar.add(Calendar.MONTH, 1);
+
+ return calendar.get(Calendar.MONTH)+"";
+
+ }
+
+
+ /**
+ *
+ * <p>获得指定日期的年.</p>
+ * @param date 指定日期
+ * @return 返回日期的年.如果{@link java.util.Date}为<code>null</code>,抛出异常.
+ * @throws NullPointerException
+ */
+ public static String getYYFromDate(Date date) {
+
+ if (null==date) {
+ throw new NullPointerException();
+ }
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(date);
+
+ return calendar.get(Calendar.YEAR)+"";
+
+ }
+
+
+ /**
+ *
+ * <p>返回两个日期之间的所有天数,放入集合{@link List}中.</p>
+ * <pre>
+ * DateUtil.getDateList(DateUtil.convertStringToDate(DateUtil.DATE_PATTERN_YYYY_MM_DD,
+ * "2010-10-22"),new Date()) = list
+ * </pre>
+ * @param begin 开始时间
+ * @param end 结束时间
+ * @return 返回两个日期相隔时间集合
+ * @throws NullPointerException
+ */
+ public static List<Date> getDateList(Date begin, Date end) {
+
+ if (null == begin || null == end ) {
+ throw new NullPointerException();
+ }
+
+ List<Date> result = new ArrayList<Date>();
+ Calendar calendar1 = Calendar.getInstance();
+ Calendar calendar2 = Calendar.getInstance();
+ calendar1.setTime(begin);
+ calendar2.setTime(end);
+ while (calendar1.before(calendar2)) {
+ result.add(calendar1.getTime());
+ calendar1.add(Calendar.DAY_OF_MONTH, 1);
+ }
+
+ return result;
+
+ }
+
+ /**
+ *
+ * <p>根据两个日期获得之间所有的工作日期返回一个日期数组 (工作日不包括星期六和星期日)</p>
+ * <pre>
+ * DateUtil.getWorkingdayList(DateUtil.convertStringToDate(TimeConstants.YYYY_MM_DD,
+ "2010-10-15"),new Date()) = list
+ * </pre>
+ * @param begin 开始日期
+ * @param end 结束日期
+ * @return 返回两个日期相隔时间集合
+ * @throws NullPointerException
+ */
+ public static List<Date> getWorkingdayList(Date begin,
+ Date end) {
+ if (null == begin || null == end ) {
+ throw new NullPointerException();
+ }
+ List<Date> list = getDateList(begin, end);
+ List<Date> result = new ArrayList<Date>();
+ Calendar calendar = Calendar.getInstance();
+
+ for (int i = 0; i < list.size(); i++) {
+
+ calendar.setTime(list.get(i));
+ if (calendar.get(Calendar.DAY_OF_WEEK) == 1
+ || calendar.get(Calendar.DAY_OF_WEEK) == 7) {
+ continue;
+ } else {
+ result.add(list.get(i));
+ }
+
+ }
+ return result;
+ }
+
+ /**
+ *
+ * <p>根据日期类型的数组获得数组内所有日期对应的星期X列表</p>
+ * @param list 日期类型的数组
+ * @return 星期X列表
+ */
+ public static List<String> getListOfDayOfWeek(List<Date> list) {
+
+ List<String> result = new ArrayList<String>();
+ Calendar calendar = Calendar.getInstance();
+ for (Date date:list) {
+ calendar.setTime(date);
+ switch (calendar.get(Calendar.DAY_OF_WEEK)) {
+ case 1:
+ result.add("星期天");
+ break;
+ case 2:
+ result.add("星期一");
+ break;
+ case 3:
+ result.add("星期二");
+ break;
+ case 4:
+ result.add("星期三");
+ break;
+ case 5:
+ result.add("星期四");
+ break;
+ case 6:
+ result.add("星期五");
+ break;
+ case 7:
+ result.add("星期六");
+ break;
+ default:
+ break;
+ }
+
+ }
+ return result;
+ }
+
+
+ /**
+ *
+ * <p>将日期,转换成10进制日期</p>
+ * <p>
+ * pattern需跟date格式相同,才可进行转换.转换后的长整型.
+ * </p>
+ * <pre>
+ * DateUtil.convertStringToTimestamp(TimeConstants.YYYY_MM_DD, "2010-10-11") = 1286726400
+ * </pre>
+ * @param date 时间值
+ * @param pattern 描述日期与格式
+ * @throws NullPointerException
+ * @see #convertTimestampToString(long, String)
+ * @return 返回10进制时间值字符串
+ */
+ public static long convertStringToTimestamp(String date,
+ String pattern){
+
+ if(StringUtil.isEmpty(date) || StringUtil.isEmpty(pattern)) {
+ throw new NullPointerException("参数为NULL");
+ }
+
+ long time = 0L;
+ simpleDateFormat = new SimpleDateFormat(pattern);
+ try {
+ time = simpleDateFormat.parse(date).getTime() / 1000;
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return time;
+
+ }
+
+
+ /**
+ *
+ * <p>将10进制,转换日期字符串类型.</p>
+ * <pre>
+ * DateUtil.convertTimestampToString(TimeConstants.YYYY_MM_DD, 1286726400l) = "2010-10-11 00:00:00"
+ * </pre>
+ * @param time10 时间戳值
+ * @param pattern 描述日期与格式
+ * @see #getFormatDate(Date, String)
+ * @see #convertStringToTimestamp(String, String)
+ * @return 返回日期字符串
+ * @throws NullPointerException
+ */
+ public static String convertTimestampToString(
+ long time10, String pattern) {
+
+ if(StringUtil.isEmpty(pattern)){
+ throw new NullPointerException("参数为NULL");
+ }
+ Date date = new Date();
+ date.setTime(time10 * 1000);
+ return getFormatDate(date,pattern);
+ }
+
+ /**
+ *
+ * <p>
+ * 将日期转变为字符串的表现形式.
+ * </p>
+ * <p>
+ * 日期格式可以参考本类提供的日期常量,也可自己定义日期格式.
+ * 当<code>pattern</code> 或 <code>date</code> 为空时,抛出空指针异常.
+ * </p>
+ * <pre>
+ * DateUtil.getFormatDate("yyyyMMddHHmmss", new Date()) = "20101102174448"
+ * </pre>
+ * @param date 解析的日期值
+ * @param pattern 描述日期与时间格式
+ * @return 返回日期的字符串表现形式.
+ * @throws NullPointerException
+ */
+ public static String getFormatDate(Date date , String pattern) {
+
+ if(StringUtil.isEmpty(pattern) || StringUtil.isEmpty(date)){
+ throw new NullPointerException("参数为NULL");
+ }
+ simpleDateFormat = new SimpleDateFormat(pattern);
+
+ return simpleDateFormat.format(date);
+ }
+
+
+ /**
+ *
+ * <p>通过字符串日期类型,转换为Date类型日期.</p>
+ * <p>
+ * pattern格式,需跟提供的日期字符串格式相统一,否则解析异常返回NULL值。
+ * </P>
+ * <pre>
+ * DateUtil.convertStringToDate(TimeConstants.YYYY_MM_DD, "2010-09-11") = date类型日期
+ * DateUtil.convertStringToDate(TimeConstants.YYYY_MM_DD_HH_MM, "2010-09-11") = NULL.
+ * </pre>
+ * @param date 字符串类型日期.
+ * @param pattern 描述日期与时间格式.
+ * @return 返回解析后的{@link java.util.Date }类型日期.
+ * @throws NullPointerException
+ */
+ public static Date convertStringToDate(String date,
+ String pattern) {
+
+ if (StringUtil.isEmpty(date) || StringUtil.isEmpty(pattern)) {
+ throw new NullPointerException();
+ }
+ simpleDateFormat = new SimpleDateFormat(pattern);
+ Date parseDate = null;
+
+ try {
+ parseDate = simpleDateFormat.parse(date);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+
+ return parseDate;
+ }
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/DateUtils.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/DateUtils.java
new file mode 100644
index 0000000..5b87f09
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/DateUtils.java
@@ -0,0 +1,822 @@
+package com.mesalab.tool.utils;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Lists;
+import org.joda.time.*;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ *
+ * <p>时间/日期处理工具类</p>
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2010-11-8 下午04:48:57
+ */
+public class DateUtils implements TimeConstants {
+
+ /**
+ *<p>Description:抑制默认的构造器,避免实例化对象 </p>
+ */
+ private DateUtils() {
+
+ }
+
+ /** <p>获得当前日期,格式为默认yyyy-MM-dd.</p>
+ * <pre>
+ * DateUtil.getCurrentDate() = "2010-11-02"
+ * </pre>
+ * @see #getCurrentDate(String)
+ * @return String 返回标准日期格式(yyyy-MM-dd)
+ */
+ public static String getCurrentDate() {
+
+ DateTime dateTime = DateTime.now();
+
+ return dateTime.toString(TimeConstants.YYYY_MM_DD);
+ }
+
+
+ /**
+ *
+ * <p>
+ * 获得当前时间.
+ * 如果pattern为空,将抛出{@link NullPointerException}
+ * </p>
+ * <pre>
+ * DateUtil.getCurrentDate(TimeConstants.YYYY_MM_DD) = "2010-11-02"
+ * DateUtil.getCurrentDate("yyyy-MM-dd HH:mm:ss") = "2010-11-02 17:20:59"
+ * </pre>
+ * @param pattern 描述日期和时间格式.
+ * @return 当前日期
+ *
+ */
+ public static String getCurrentDate(String pattern) {
+
+ if(StringUtil.isEmpty(pattern)){
+ throw new NullPointerException("未规定时间格式...");
+ }
+ DateTime dateTime = DateTime.now();
+ return dateTime.toString(pattern);
+ }
+
+
+ /**
+ *
+ * <p> 获得昨天时间.通过指定日期和时间格式,具体可参考本类提供的时间格式常量.</p>
+ * <pre>
+ * DateUtil.getDateOfYesterday(TimeConstants.YYYY_MM_DD_HH24_MM_SS) = "2010-11-04 16:59:13"
+ * </pre>
+ * @param pattern 描述日期和时间格式
+ * @see #getFormatDate(Date, String)
+ * @return String 返回日期的字符串表现形式值.
+ */
+ public static String getDateOfYesterday(String pattern) {
+ DateTime dateTime = new DateTime();
+ DateTime yesterday = dateTime.minusDays(1);
+ return yesterday.toString(pattern);
+
+ }
+
+
+
+ /**
+ *
+ * <p>
+ * 得到距离当天<code>offset</code>天数的某天日期,通过 <code>offset</code> 的值(+/-)来确定增减计算.
+ * </p>
+ * <pre>
+ * 当天日期: 2010-11-05
+ * DateUtil.getSomeDate("yyyy-MM-dd", 2) = 2010-11-07
+ * DateUtil.getSomeDate("yyyy-MM-dd", -2) = 2010-11-03
+ * DateUtil.getSomeDate("yyyy-MM-dd", 0) = 2010-11-05
+ * </pre>
+ * @param pattern 描述日期和时间格式
+ * @param offset 描述增加\减少几日,为0时为当前日期.
+ * @see #getFormatDate(Date, String)
+ * @return 返回日期格式的字符串
+ */
+
+ public static String getSomeDate(String pattern, int offset) {
+ DateTime dateTime = new DateTime();
+ DateTime someDate = dateTime.withFieldAdded(DurationFieldType.days(), offset);
+ return someDate.toString(pattern);
+ }
+
+ /**
+ *
+ * <p>
+ * 得到距离指定时间<code>offset</code>天数的时间,通过 <code>offset</code> 的值(+/-)来确定增减计算.
+ * </p>
+ * <pre>
+ * 当天日期: 2010-11-05
+ * DateUtil.getSomeDate("yyyy-MM-dd", 2) = 2010-11-07
+ * DateUtil.getSomeDate("yyyy-MM-dd", -2) = 2010-11-03
+ * DateUtil.getSomeDate("yyyy-MM-dd", 0) = 2010-11-05
+ * </pre>
+ * @param date 时间
+ * @param offset 描述增加\减少几日,为0时为当前日期.
+ * @return 返回日期格式的字符串
+ */
+
+ public static Date getSomeDate(Date date, int offset) {
+ DateTime dateTime = new DateTime(date);
+ return dateTime.plusDays(offset).toDate();
+ }
+
+
+
+ /**
+ *
+ * <p>
+ * 得到距离当前时间<code>offset</code>小时的时间,通过 <code>offset</code> 的值(+/-)来确定增减计算.
+ * </p>
+ * <pre>
+ * 当天时间: 2018-11-05 11:13:22
+ * DateUtil.getSomeHour(date, 2) = 2018-11-05 13:13:22
+ * DateUtil.getSomeHour(date, -2) = 2018-11-05 09:13:22
+ * DateUtil.getSomeHour(date, 0) = 2018-11-05 11:13:22
+ * </pre>
+ * @param date 时间
+ * @param offset 描述增加\减少小时数,为0时为当前日期.
+ * @return 返回距离当前时间小时数的时间
+ */
+ public static Date getSomeHour(Date date, int offset) {
+ DateTime dateTime = new DateTime(date);
+ return dateTime.plusHours(offset).toDate();
+ }
+
+
+
+ /**
+ *
+ * <p>
+ * 得到距离当前时间<code>offset</code>分钟数的时间,通过 <code>offset</code> 的值(+/-)来确定增减计算.
+ * </p>
+ * <pre>
+ * 当天时间: 2018-11-05 11:13:22
+ * DateUtil.getSomeMinute(date, 2) = 2018-11-05 11:15:22
+ * DateUtil.getSomeMinute(date, -2) = 2018-11-05 11:11:22
+ * DateUtil.getSomeMinute(date, 0) = 2018-11-05 11:13:22
+ * </pre>
+ * @param date 时间
+ * @param offset 描述增加\减少分钟数,为0时为当前日期.
+ * @return 返回距离当前时间分钟数的时间
+ */
+ public static Date getSomeMinute(Date date, int offset) {
+ DateTime dateTime = new DateTime(date);
+ return dateTime.plusMinutes(offset).toDate();
+ }
+
+
+ /**
+ *
+ * <p>
+ * 得到距离当前时间格式化分钟后的时间,5分钟倍数
+ * </p>
+ * <pre>
+ * 当天时间: 2018-11-05 11:13:22
+ * DateUtil.getFormatMinute(date) = 2018-11-05 11:10:00
+ * </pre>
+ * @param date 时间
+ * @return 返回距离当前时间5分钟倍数的时间
+ */
+ public static Date getGranularityFiveMinute(Date date) {
+ return getTimeFloor(date, "PT5M");
+ }
+
+
+
+ /**
+ *
+ * <p>
+ * 得到距离当前时间<code>offset</code>秒数的时间,通过 <code>offset</code> 的值(+/-)来确定增减计算.
+ * </p>
+ * <pre>
+ * 当天时间: 2018-11-05 11:13:22
+ * DateUtil.getSomeSecond(date, 2) = 2018-11-05 11:13:24
+ * DateUtil.getSomeSecond(date, -2) = 2018-11-05 11:13:20
+ * DateUtil.getSomeSecond(date, 0) = 2018-11-05 11:13:22
+ * </pre>
+ * @param date 时间
+ * @param offset 描述增加\减少秒数,为0时为当前日期.
+ * @return 返回距离当前时间秒数的时间
+ */
+ public static Date getSomeSecond(Date date, int offset) {
+ DateTime dateTime = new DateTime(date);
+ return dateTime.plusSeconds(offset).toDate();
+ }
+
+
+
+ /**
+ *
+ * <p>获得指定日期当前周第一天</p>
+ * <pre>
+ * 当前时间 2018-12-26 11:47:00
+ * DateUtil.getFirstDayOfWeek(new Date(),TimeConstants.YYYY_MM_DD_HH24_MM_SS) = "2018-12-24 00:00:00"
+ * </pre>
+ * @param date 指定日期.
+ * @param pattern 描述日期和时间格式
+ * @return 返回日期格式的字符串
+ */
+ public static String getFirstDayOfWeek(Date date, String pattern) {
+
+ if (StringUtil.isEmpty(pattern) || StringUtil.isEmpty(date)) {
+ throw new NullPointerException("时间不能为空或解析格式不能为空");
+ }
+
+ DateTime firstDay = DateTime.parse(getFormatDate(date, TimeConstants.YYYY_MM_DD))
+ .dayOfWeek().setCopy(1).toDateTime();
+
+ return firstDay.toString(pattern);
+ }
+
+
+ /**
+ *
+ * <p>获得指定日期当前周最后一天</p>
+ * <pre>
+ * 当前时间 2018-12-26 11:47:00
+ * DateUtil.getFirstDayOfWeek(new Date(),TimeConstants.YYYY_MM_DD_HH24_MM_SS) = "2018-12-30 23:59:59"
+ * </pre>
+ * @param date 指定日期.
+ * @param pattern 描述日期和时间格式
+ * @return 返回日期格式的字符串
+ */
+ public static String getLastDayOfWeek(Date date, String pattern) {
+
+ if (StringUtil.isEmpty(pattern) || StringUtil.isEmpty(date)) {
+ throw new NullPointerException("时间不能为空或解析格式不能为空");
+ }
+
+ DateTime lastDay = new DateTime(date)
+ .dayOfWeek().withMaximumValue().millisOfDay().withMaximumValue().toDateTime();
+
+ return lastDay.toString(pattern);
+ }
+
+
+
+
+
+
+ /**
+ *
+ * <p>获得指定日期当月第一天</p>
+ * <pre>
+ * DateUtil.getFirstDayOfMonth(new Date(), TimeConstants.YYYY_MM_DD_HH24_MM_SS) = "2010-11-01 00:00:00"
+ * </pre>
+ * @param date 指定日期.
+ * @param pattern 描述日期和时间格式
+ * @return 返回日期格式的字符串
+ */
+ public static String getFirstDayOfMonth(Date date, String pattern) {
+
+ if (StringUtil.isEmpty(pattern) || StringUtil.isEmpty(date)) {
+ throw new NullPointerException("时间不能为空或解析格式不能为空");
+ }
+
+ DateTime firstDay = DateTime.parse(getFormatDate(date, TimeConstants.YYYY_MM_DD))
+ .dayOfMonth().setCopy(1).toDateTime();
+
+ return firstDay.toString(pattern);
+ }
+
+
+ /**
+ *
+ * <p>获得指定日期当月最后一天</p>
+ * <pre>
+ * DateUtil.getLastDayOfMonth(new Date(), TimeConstants.YYYY_MM_DD_HH24_MM_SS) = "2010-11-30 23:59:59"
+ * </pre>
+ * @param date 指定日期
+ * @param pattern 描述日期和时间格式
+ * @return 返回日期格式的字符串
+ */
+ public static String getLastDayOfMonth(Date date,
+ String pattern) {
+
+ if (StringUtil.isEmpty(pattern) || StringUtil.isEmpty(date)) {
+ throw new NullPointerException("时间不能为空或解析格式不能为空");
+ }
+
+ DateTime lastDay = new DateTime(date)
+ .dayOfMonth().withMaximumValue().millisOfDay().withMaximumValue().toDateTime();
+
+ return lastDay.toString(pattern);
+ }
+
+
+
+
+
+ /**
+ *
+ * <p>获得指定日期的日.</p>
+ * @param date 日期值
+ * @return 返回日期的日.如果{@link java.util.Date}为<code>null</code>,抛出异常.
+ * @throws NullPointerException
+ */
+ public static String getDDFromDate(Date date) {
+ if (StringUtil.isEmpty(date)) {
+ throw new NullPointerException("date 不能为空");
+ }
+
+ return String.valueOf(new DateTime(date).getDayOfMonth());
+
+ }
+
+
+ /**
+ *
+ * <p>获得指定日期的月.</p>
+ * @param date 指定日期
+ * @return 返回日期的月.如果{@link java.util.Date}为<code>null</code>,抛出异常.
+ * @throws NullPointerException
+ */
+ public static String getMMFromDate(Date date) {
+
+ if (StringUtil.isEmpty(date)) {
+ throw new NullPointerException("date 不能为空");
+ }
+ return String.valueOf(new DateTime(date).getMonthOfYear());
+
+ }
+
+
+ /**
+ *
+ * <p>获得指定日期的年.</p>
+ * @param date 指定日期
+ * @return 返回日期的年.如果{@link java.util.Date}为<code>null</code>,抛出异常.
+ * @throws NullPointerException
+ */
+ public static String getYYFromDate(Date date) {
+
+ if (StringUtil.isEmpty(date)) {
+ throw new NullPointerException("date 不能为空");
+ }
+ return String.valueOf(new DateTime(date).getYear());
+
+ }
+
+
+
+
+
+ /**
+ *
+ * <p>返回两个日期之间的所有天数,放入集合{@link List}中.</p>
+ * <pre>
+ * DateUtil.getDateList(DateUtil.convertStringToDate(DateUtil.DATE_PATTERN_YYYY_MM_DD,
+ * "2010-10-22"),new Date()) = list
+ * </pre>
+ * @param begin 开始时间
+ * @param end 结束时间
+ * @return 返回两个日期相隔时间集合
+ * @throws NullPointerException
+ */
+ public static List<Date> getEveryDay(Date begin, Date end) {
+
+ if (StringUtil.isEmpty(begin) || StringUtil.isEmpty(end)) {
+ throw new NullPointerException("date 不能为空");
+ }
+ List<Date> result = new ArrayList<Date>();
+ DateTime beginDate = new DateTime(begin);
+ DateTime endDate = new DateTime(end);
+
+ while (endDate.isAfter(beginDate)) {
+ result.add(beginDate.toDate());
+ beginDate = beginDate.plusDays(1);
+ }
+
+
+
+
+ return result;
+
+ }
+
+
+ /**
+ * 以基准日期为起点向左获取所有时间点列表。
+ * @param benchmarkDate 基准时间
+ * @param endDate 终止时间,用于定义时间数据范围
+ * @param period 参见ISO8601 对durations定义,例如PT5M,P1W; 约束不可为复合周期(P1YT5M)
+ * @return
+ */
+ public static List<Date> getLeftDateRange(Date benchmarkDate, Date endDate, String period) {
+
+ if (StringUtil.isEmpty(endDate) || StringUtil.isEmpty(benchmarkDate)) {
+ throw new NullPointerException("benchmarkDate and endDate is not null.");
+ }
+
+ List<Date> dateList = Lists.newArrayList();
+
+ Period granularityPeriod = Period.parse(period);
+ DateTime benchmarkTime = new DateTime (benchmarkDate);
+ DateTime endTime = new DateTime((endDate));
+ while(benchmarkTime.compareTo(endTime) > 0) {
+ benchmarkTime = benchmarkTime.minus(granularityPeriod);
+ dateList.add(benchmarkTime.toDate());
+ }
+
+ return dateList;
+
+ }
+
+ /**
+ * 以基准日期为起点向右获取所有时间点列表。
+ * @param benchmarkDate 基准时间
+ * @param endDate 终止时间,用于定义时间数据范围
+ * @param period 参见ISO8601 对durations定义,例如PT5M,P1W; 约束不可为复合周期(P1YT5M)
+ * @return
+ */
+ public static List<Date> getRightDateRange(Date benchmarkDate, Date endDate, String period) {
+
+ if (StringUtil.isEmpty(endDate) || StringUtil.isEmpty(benchmarkDate)) {
+ throw new NullPointerException("benchmarkDate and endDate is not null.");
+ }
+
+ List<Date> dateList = Lists.newArrayList();
+
+ Period granularityPeriod = Period.parse(period);
+ DateTime benchmarkTime = new DateTime (benchmarkDate);
+ DateTime endTime = new DateTime((endDate));
+ while(benchmarkTime.compareTo(endTime) <= 0) {
+ dateList.add(benchmarkTime.toDate());
+ benchmarkTime = benchmarkTime.plus(granularityPeriod);
+ }
+
+ return dateList;
+
+ }
+
+ /**
+ * 按照时间粒度,获取指定时间范围内的所有时间点。
+ * 例如:2019-10-11 10:00:00/2019-10-11 10:20:00,时间周期每5分钟(PT5M),
+ * 则获取结果为[2019-10-11 10:00:00,2019-10-11 10:05:00,2019-10-11 10:10:00,2019-10-11 10:15:00,2019-10-11 10:20:00]
+ * @param startDate 起始时间
+ * @param endDate 终止时间
+ * @param period 时间粒度 参见ISO8601 对durations定义,例如PT5M,P1W; 约束不可为复合周期(P1YT5M)
+ * @return
+ */
+ public static List<Date> getDateRange(Date startDate, Date endDate, String period) {
+
+ if (StringUtil.isEmpty(startDate) || StringUtil.isEmpty(endDate)) {
+ throw new NullPointerException("startDate and endDate is not null.");
+ }
+
+
+ List<Date> dateList = Lists.newArrayList();
+
+ Period granularityPeriod = Period.parse(period);
+
+ DateTime floorStartDate = new DateTime(getTimeFloor(startDate, period));
+
+ DateTime endDateTime = new DateTime(endDate);
+
+
+ while(floorStartDate.compareTo(endDateTime) <= 0) {
+ dateList.add(floorStartDate.toDate());
+ floorStartDate = floorStartDate.plus(granularityPeriod);
+ }
+
+
+ return dateList;
+ }
+
+
+
+
+
+
+ /**
+ *
+ * <p>根据两个日期获得之间所有的工作日期返回一个日期数组 (工作日不包括星期六和星期日)</p>
+ * <pre>
+ * DateUtil.getWorkingdayList(DateUtil.convertStringToDate(TimeConstants.YYYY_MM_DD,
+ "2010-10-15"),new Date()) = list
+ * </pre>
+ * @param begin 开始日期
+ * @param end 结束日期
+ * @return 返回两个日期相隔时间集合
+ * @throws NullPointerException
+ */
+ public static List<Date> getWorkingdayList(Date begin,
+ Date end) {
+ if (null == begin || null == end ) {
+ throw new NullPointerException();
+ }
+ List<Date> list = getEveryDay(begin, end);
+ List<Date> result = new ArrayList<Date>();
+ for (int i = 0; i < list.size(); i++) {
+
+ if (new DateTime(list.get(i)).getDayOfWeek() == 6
+ || new DateTime(list.get(i)).getDayOfWeek() == 7) {
+ continue;
+ } else {
+ result.add(list.get(i));
+ }
+ }
+
+ return result;
+ }
+
+
+ /**
+ *
+ * <p>根据日期类型的数组获得数组内所有日期对应的星期X列表</p>
+ * @param list 日期类型的数组
+ * @return 星期X列表
+ */
+ public static List<String> getListOfDayOfWeek(List<Date> list) {
+
+ List<String> result = new ArrayList<String>();
+
+ for (Date date:list) {
+ DateTime dateTime = new DateTime(date);
+
+ switch (dateTime.getDayOfWeek()) {
+
+ case DateTimeConstants.SUNDAY:
+ result.add("星期日");
+ break;
+ case DateTimeConstants.MONDAY:
+ result.add("星期一");
+ break;
+ case DateTimeConstants.TUESDAY:
+ result.add("星期二");
+ break;
+ case DateTimeConstants.WEDNESDAY:
+ result.add("星期三");
+ break;
+ case DateTimeConstants.THURSDAY:
+ result.add("星期四");
+ break;
+ case DateTimeConstants.FRIDAY:
+ result.add("星期五");
+ break;
+ case DateTimeConstants.SATURDAY:
+ result.add("星期六");
+ break;
+ default:
+ break;
+ }
+
+ }
+ return result;
+ }
+
+
+ /**
+ *
+ * <p>将日期,转换成10进制日期</p>
+ * <p>
+ * pattern需跟date格式相同,才可进行转换.转换后的长整型.
+ * </p>
+ * <pre>
+ * DateUtil.convertStringToTimestamp(TimeConstants.YYYY_MM_DD, "2010-10-11") = 1286726400
+ * </pre>
+ * @param date 时间值
+ * @param pattern 描述日期与格式
+ * @throws NullPointerException
+ * @see #convertTimestampToString(long, String)
+ * @return 返回10进制时间值字符串
+ */
+ public static long convertStringToTimestamp(String date, String pattern) {
+
+ if(StringUtil.isEmpty(date) || StringUtil.isEmpty(pattern)) {
+ throw new NullPointerException("date 与 pattern 不能为空");
+ }
+
+ DateTimeFormatter format = DateTimeFormat.forPattern(pattern);
+ return DateTime.parse(date, format).toDateTime().getMillis() / 1000;
+
+ }
+
+
+
+ /**
+ *
+ * <p>将10进制,转换日期字符串类型.</p>
+ * <pre>
+ * DateUtil.convertTimestampToString(TimeConstants.YYYY_MM_DD, 1286726400l) = "2010-10-11 00:00:00"
+ * </pre>
+ * @param time10 时间戳值
+ * @param pattern 描述日期与格式
+ * @see #getFormatDate(Date, String)
+ * @see #convertStringToTimestamp(String, String)
+ * @return 返回日期字符串
+ * @throws NullPointerException
+ */
+ public static String convertTimestampToString(long time10, String pattern) {
+
+ if(StringUtil.isBlank(pattern)) {
+ throw new NullPointerException("pattern 不能为空");
+ }
+
+ return DateTime.now().withMillis(time10 * 1000).toString(pattern);
+ }
+
+
+
+
+
+
+
+ /**
+ *
+ * <p>
+ * 将日期转变为字符串的表现形式.
+ * </p>
+ * <p>
+ * 日期格式可以参考本类提供的日期常量,也可自己定义日期格式.
+ * 当<code>pattern</code> 或 <code>date</code> 为空时,抛出空指针异常.
+ * </p>
+ * <pre>
+ * DateUtil.getFormatDate("yyyyMMddHHmmss", new Date()) = "20101102174448"
+ * </pre>
+ * @param date 解析的日期值
+ * @param pattern 描述日期与时间格式
+ * @return 返回日期的字符串表现形式.
+ * @throws NullPointerException
+ */
+ public static String getFormatDate(Date date , String pattern) {
+
+ if(StringUtil.isEmpty(pattern) || StringUtil.isEmpty(date)){
+ throw new NullPointerException("参数为NULL......");
+ }
+ DateTime dateTime = new DateTime(date);
+
+ return dateTime.toString(pattern);
+ }
+
+ /**
+ *
+ * <p>通过字符串日期类型,转换为Date类型日期.</p>
+ * <p>
+ * pattern格式,需跟提供的日期字符串格式相统一,否则解析异常返回NULL值。
+ * </P>
+ * <pre>
+ * DateUtil.convertStringToDate(TimeConstants.YYYY_MM_DD, "2010-09-11") = date类型日期
+ * DateUtil.convertStringToDate(TimeConstants.YYYY_MM_DD_HH_MM, "2010-09-11") = NULL.
+ * </pre>
+ * @param date 字符串类型日期.
+ * @param pattern 描述日期与时间格式.
+ * @return 返回解析后的{@link java.util.Date }类型日期.
+ * @throws NullPointerException
+ */
+ public static Date convertStringToDate(String date, String pattern) {
+
+
+ if (StringUtil.isEmpty(date) || StringUtil.isEmpty(pattern)) {
+ throw new NullPointerException("date 与 pattern 不能为空");
+ }
+
+ DateTimeFormatter format = DateTimeFormat.forPattern(pattern);
+
+ return DateTime.parse(date, format).toDate();
+ }
+
+ /**
+ * 对当前时间根据粒度往下舍入时间,返回一个新的时间
+ * 例如 getTimeFloor("2019-12-12 12:32:12", "PT5M") = "2019-12-12 12:30:00"
+ * @param date
+ * @param periodGranularity
+ * @return
+ */
+ public static Date getTimeFloor(Date date, String periodGranularity) {
+
+ Period period = Period.parse(periodGranularity);
+ if (isCompoundPeriod(period)) {
+ throw new IllegalArgumentException("periodGranularity is not supported:"+ period.toString());
+ }
+
+ DateTime dateTime = new DateTime(date);
+
+ final int years = period.getYears();
+ if (years > 0) {
+ int y = dateTime.getYear();
+ y -= y % years;
+ dateTime = dateTime.withYear(y).withMonthOfYear(1).withDayOfMonth(1).withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).withMillisOfSecond(0);
+
+ return dateTime.toDate();
+ }
+
+ final int months = period.getMonths();
+ if (months > 0) {
+
+ int m = dateTime.getMonthOfYear();
+ if (m % months != m) {
+ m -= m % months;
+ }
+ dateTime = dateTime.withMonthOfYear(m).withDayOfMonth(1).withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).withMillisOfSecond(0);
+ return dateTime.toDate();
+ }
+
+
+ final int weeks = period.getWeeks();
+ if (weeks > 0) {
+ int w = dateTime.getWeekOfWeekyear();
+
+ if (w % weeks != w) {
+ w -= w % weeks;
+ }
+ dateTime = dateTime.withWeekOfWeekyear(w).withDayOfWeek(1).withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).withMillisOfSecond(0);
+
+ return dateTime.toDate();
+ }
+
+
+
+ final int days = period.getDays();
+ if (days > 0) {
+ int d = dateTime.getDayOfMonth();
+ if (d % days != d) {
+ d -= d % days;
+ }
+
+ dateTime = dateTime.withDayOfMonth(d).withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).withMillisOfSecond(0);
+ return dateTime.toDate();
+ }
+
+
+ final int hours = period.getHours();
+ if (hours > 0) {
+ int h = dateTime.getHourOfDay();
+ h -= h % hours;
+ dateTime = dateTime.withHourOfDay(h).withMinuteOfHour(0).withSecondOfMinute(0).withMillisOfSecond(0);
+ return dateTime.toDate();
+ }
+
+
+
+ final int minutes = period.getMinutes();
+ if (minutes > 0) {
+
+ int m = dateTime.getMinuteOfHour();
+ m -= m % minutes;
+
+ dateTime = dateTime.withMinuteOfHour(m).withSecondOfMinute(0).withMillisOfSecond(0);
+
+ return dateTime.toDate();
+
+ }
+
+ final int seconds = period.getSeconds();
+ if (seconds > 0) {
+
+ int s = dateTime.getSecondOfMinute();
+ s -= s % seconds;
+
+ dateTime = dateTime.withSecondOfMinute(s).withMillisOfSecond(0);
+
+ return dateTime.toDate();
+
+ }
+
+
+ return null;
+
+
+
+
+ }
+
+
+
+
+
+
+ /**
+ * 判定周期是否为复合周期,用于时序数据粒度的判定
+ * 例如:按照ISO_8601 规定Durations定义, P1DT12H 为复合周期,P1D 为单个周期
+ * @param period
+ * @return
+ */
+ private static boolean isCompoundPeriod(Period period) {
+ int[] values = period.getValues();
+ boolean single = false;
+ for (int value : values) {
+ if (value > 0) {
+ if(single) {
+ return true;
+ }
+
+ single = true;
+
+ }
+ }
+
+ return false;
+ }
+
+
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/Encodes.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/Encodes.java
new file mode 100644
index 0000000..12638bd
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/Encodes.java
@@ -0,0 +1,145 @@
+/**
+ * Copyright (c) 2005-2012 springside.org.cn
+ */
+package com.mesalab.tool.utils;
+
+import com.mesalab.tool.exception.Exceptions;
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+
+/**
+ * 封装各种格式的编码解码工具类.
+ * 1.Commons-Codec的 hex/base64 编码
+ * 2.自制的base62 编码
+ * 3.Commons-Lang的xml/html escape
+ * 4.JDK提供的URLEncoder
+ * @author darnell
+ * @version 2013-01-15
+ */
+public class Encodes {
+
+ private static final String DEFAULT_URL_ENCODING = "UTF-8";
+ private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
+
+ /**
+ * Hex编码.
+ */
+ public static String encodeHex(byte[] input) {
+ return new String(Hex.encodeHex(input));
+ }
+
+ /**
+ * Hex解码.
+ */
+ public static byte[] decodeHex(String input) {
+ try {
+ return Hex.decodeHex(input.toCharArray());
+ } catch (DecoderException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+ /**
+ * Base64编码.
+ */
+ public static String encodeBase64(byte[] input) {
+ return new String(Base64.encodeBase64(input));
+ }
+
+ /**
+ * Base64编码.
+ */
+ public static String encodeBase64(String input) {
+ try {
+ return new String(Base64.encodeBase64(input.getBytes(DEFAULT_URL_ENCODING)));
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ }
+
+
+ public static String encodeBase64(String input, String charset) {
+ try {
+ return new String(Base64.encodeBase64(input.getBytes(charset)));
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ }
+
+// /**
+// * Base64编码, URL安全(将Base64中的URL非法字符'+'和'/'转为'-'和'_', 见RFC3548).
+// */
+// public static String encodeUrlSafeBase64(byte[] input) {
+// return Base64.encodeBase64URLSafe(input);
+// }
+
+ /**
+ * Base64解码.
+ */
+ public static byte[] decodeBase64(String input) {
+ return Base64.decodeBase64(input.getBytes());
+ }
+
+ /**
+ * Base64解码.
+ */
+ public static String decodeBase64String(String input) {
+ try {
+ return new String(Base64.decodeBase64(input.getBytes()), DEFAULT_URL_ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ }
+
+ /**
+ * Base64解码.
+ */
+ public static String decodeBase64String(String input, String charset) {
+ try {
+ return new String(Base64.decodeBase64(input.getBytes()), charset);
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ }
+
+ /**
+ * Base62编码。
+ */
+ public static String encodeBase62(byte[] input) {
+ char[] chars = new char[input.length];
+ for (int i = 0; i < input.length; i++) {
+ chars[i] = BASE62[((input[i] & 0xFF) % BASE62.length)];
+ }
+ return new String(chars);
+ }
+
+
+ /**
+ * URL 编码, Encode默认为UTF-8.
+ */
+ public static String urlEncode(String part) {
+ try {
+ return URLEncoder.encode(part, DEFAULT_URL_ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+ /**
+ * URL 解码, Encode默认为UTF-8.
+ */
+ public static String urlDecode(String part) {
+
+ try {
+ return URLDecoder.decode(part, DEFAULT_URL_ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/FormatUtils.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/FormatUtils.java
new file mode 100644
index 0000000..af6590d
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/FormatUtils.java
@@ -0,0 +1,236 @@
+package com.mesalab.tool.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.net.InternetDomainName;
+
+public class FormatUtils {
+
+ protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ /**
+ * 将List&lt;HashMap&lt;String,Object&gt;&gt;中HashMap的key全部转化为变量形式,<br>
+ * 如{"BRH_ID":"1234","BRH_NAME":"机构"}改为{"brhId":"1234","brhName":"机构"}
+ *
+ * @param list
+ * @return List<HashMap<String, Object>>
+ */
+ public static List<HashMap<String, Object>> formatHashMapKeyInList(List<HashMap<String, Object>> list) {
+ List result = new ArrayList();
+ // 遍历list后进行格式化列表元素
+ if (list != null) {
+ for (HashMap<String, Object> h : list) {
+ // 将hashMap的key转化为驼峰格式,如{"BRH_ID":"1234"}改为{"brhId":"1234"}
+ result.add(formatHashMapKey(h));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * 将hashMap的key转化为驼峰格式,如{"BRH_ID":"1234","BRH_NAME":"机构"}改为{"brhId":"1234",
+ * "brhName":"机构"}
+ *
+ * @param hashMap
+ * @return HashMap<String, Object>
+ */
+ public static HashMap<String, Object> formatHashMapKey(HashMap<String, Object> hashMap) {
+ HashMap result = new HashMap();
+ String key = null;
+ // 遍历map
+ for (Entry<String, Object> e : (Set<Entry<String, Object>>) hashMap.entrySet()) {
+ key = (String) e.getKey();
+ // 将hashMap的key转化为驼峰格式
+ key = formatDBNameToVarName(key);
+ // 封装为新的map
+ result.put(key, e.getValue());
+ }
+ // 返回格式化后的map
+ return result;
+ }
+
+ /**
+ * 数据库列名转化为属性名,如DEAL_ID=dealId; <br>
+ * 不能保证完全正确,如DBUTIL不会智能的转化为DBUtil,而会转化为dbutil, <br>
+ * 规则为全部转化为单词,然后首字母小写
+ *
+ * @param DBName
+ * @return String
+ */
+ public static String formatDBNameToVarName(String DBName) {
+ StringBuilder result = new StringBuilder("");
+ // 以"_"分割
+ String[] DBNameArr = DBName.split("_");
+ for (int i = 0, j = DBNameArr.length; i < j; i++) {
+ // 获取以"_"分割后的字符数组的每个元素的第一个字母,
+ result.append(DBNameArr[i].charAt(0));
+ // 将其他字符转换成小写
+ result.append(DBNameArr[i].substring(1).toLowerCase());
+ }
+ char c0 = result.charAt(0);
+ if (c0 >= 'A' && c0 <= 'Z') {
+ c0 = (char) (c0 + 'a' - 'A');
+ }
+ result.setCharAt(0, c0);
+ return result.toString();
+ }
+
+ private FormatUtils(Builder builder) {
+ init(builder);
+ }
+
+ private synchronized void init(Builder builder) {
+ try {
+
+ if (builder.isDefalult) {
+ logger.info("FormatUtils begin with default PZ.");
+ } else {
+ logger.info("FormatUtils begin with user-defined PZ.");
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static final class Builder {
+ boolean isDefalult;
+
+ public Builder(boolean isDefalult) {
+ this.isDefalult = isDefalult;
+ }
+
+ public FormatUtils build() {
+ return new FormatUtils(this);
+ }
+
+ }
+
+ /**
+ * 获取域名的顶级私有域名
+ * 例如:getTopPrivateDomain('www.google.com.hk') ,返回 google.com.hk
+ * @param domain 网站域名
+ * @return 顶级私有域名
+ */
+ public static String getTopPrivateDomain(String domain) {
+
+ domain = getDomain(domain);
+
+ if (StringUtil.isBlank(domain) || !InternetDomainName.isValid(domain)) {
+ return StringUtil.EMPTY;
+ }
+
+ InternetDomainName internetDomainName = InternetDomainName.from(domain);
+
+ if (internetDomainName.isUnderPublicSuffix()) {
+ return internetDomainName.topPrivateDomain().toString();
+ } else {
+ return StringUtil.EMPTY;
+
+ }
+
+ }
+
+ /**
+ * 根据邮箱发件人或收件人地址获取域名信息
+ * @param email 发件人或收件人地址
+ * @return
+ */
+ public static String getEmailDomain(String email) {
+ if (StringUtil.isBlank(email)) {
+ return StringUtil.EMPTY;
+ }
+
+ if (email.indexOf("@") < 0) {
+ return StringUtil.EMPTY;
+ }
+
+
+ return email.substring(email.indexOf("@") + 1);
+ }
+
+
+
+ /**
+ *
+ * <p>通过给定url获取域名地址.</p>
+ * <p>
+ * 获得域名信息需去除 http/https/ftp 与 www 一些头信息,获取有效地址.
+ * </p>
+ * <pre>
+ * StringUtil.getDomain("http://www.baidu.com") = "baidu.com"
+ * </pre>
+ * @param url 地址
+ * @return 返回截取后的域名地址
+ */
+ public static String getDomain(String url) {
+
+ if(StringUtil.isBlank(url)){
+ return StringUtil.EMPTY;
+ }
+
+ if (url.indexOf("http://") >= 0) {
+ url = url.substring("http://".length(), url.length());
+ } else if (url.indexOf("https://", 0) >= 0) {
+ url = url.substring("https://".length(), url.length());
+ } else if (url.indexOf("ftp://", 0) >= 0) {
+ url = url.substring("ftp://".length(), url.length());
+ } else {
+ url = url;
+ }
+
+ if (url.indexOf("www.") == 0) {
+ url = url.substring(url.indexOf(".") + 1, url.length());
+ }
+
+ if (url.indexOf(":") >= 0) {
+ url = url.substring(0, url.indexOf(":"));
+ }
+
+ if (url.indexOf("/", 0) >= 0) {
+ url = url.substring(0, url.indexOf("/", 1));
+ }
+
+ if (url.indexOf("?") >= 0) {
+ url = url.substring(0, url.indexOf("?"));
+ }
+
+
+ return url;
+ }
+
+ /**
+ * 雪花模型生成id
+ * @param workerId
+ * @param dataCenterId
+ * @return 全局唯一id
+ */
+ public long getSnowflakeId(long workerId, long dataCenterId) {
+ return SnowflakeId.generateId(workerId, dataCenterId);
+ }
+
+ /**
+ * 雪花模型生成id
+ * 依赖于zookeeper
+ * @param zookeeperIp
+ * @param dataCenterId
+ * @return 全局唯一id
+ */
+ public long getSnowflakeId(String zookeeperIp, long dataCenterId) {
+
+ return SnowflakeId.generateId(zookeeperIp, dataCenterId);
+ }
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/GalaxyDataBaseReader.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/GalaxyDataBaseReader.java
new file mode 100644
index 0000000..b7e20a5
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/GalaxyDataBaseReader.java
@@ -0,0 +1,197 @@
+package com.mesalab.tool.utils;/**
+ * Created by dell on 2018-10-8.
+ */
+
+import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.maxmind.db.*;
+import com.maxmind.geoip2.exception.AddressNotFoundException;
+import com.maxmind.geoip2.exception.GeoIp2Exception;
+import com.maxmind.geoip2.model.*;
+import com.mesalab.tool.domain.LocationResponse;
+import com.mesalab.tool.domain.JsonInjector;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @ClassName GalaxyDataBaseReader
+ * @Description TODO
+ * @Author dell
+ * @Date 2018-10-8 18:30
+ * @Version 1.0
+ **/
+public class GalaxyDataBaseReader {
+
+ private final Reader reader;
+
+ private final ObjectMapper om;
+
+ private final List<String> locales;
+
+ private GalaxyDataBaseReader(Builder builder) throws IOException {
+ if (builder.stream != null) {
+ this.reader = new Reader(builder.stream, builder.cache);
+ } else if (builder.database != null) {
+ this.reader = new Reader(builder.database, builder.mode, builder.cache);
+ } else {
+ // This should never happen. If it does, review the Builder class
+ // constructors for errors.
+ throw new IllegalArgumentException(
+ "Unsupported Builder configuration: expected either File or URL");
+ }
+ this.om = new ObjectMapper();
+ this.om.configure(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS, false);
+ this.om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
+ false);
+ this.om.configure(
+ DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
+ this.locales = builder.locales;
+ }
+
+ /**
+ * <p>
+ * Constructs a Builder for the {@code DatabaseReader}. The file passed to
+ * it must be a valid GeoIP2 database file.
+ * </p>
+ * <p>
+ * {@code Builder} creates instances of {@code DatabaseReader}
+ * from values set by the methods.
+ * </p>
+ * <p>
+ * Only the values set in the {@code Builder} constructor are required.
+ * </p>
+ */
+ public static final class Builder {
+ final File database;
+ final InputStream stream;
+
+ List<String> locales = Collections.singletonList("en");
+ Reader.FileMode mode = Reader.FileMode.MEMORY_MAPPED;
+ NodeCache cache = NoCache.getInstance();
+
+ /**
+ * @param stream the stream containing the GeoIP2 database to use.
+ */
+ public Builder(InputStream stream) {
+ this.stream = stream;
+ this.database = null;
+ }
+
+ /**
+ * @param database the GeoIP2 database file to use.
+ */
+ public Builder(File database) {
+ this.database = database;
+ this.stream = null;
+ }
+
+ /**
+ * @param val List of locale codes to use in name property from most
+ * preferred to least preferred.
+ * @return Builder object
+ */
+ public Builder locales(List<String> val) {
+ this.locales = val;
+ return this;
+ }
+
+ /**
+ * @param cache backing cache instance
+ * @return Builder object
+ */
+ public Builder withCache(NodeCache cache) {
+ this.cache = cache;
+ return this;
+ }
+
+ /**
+ * @param val The file mode used to open the GeoIP2 database
+ * @return Builder object
+ * @throws java.lang.IllegalArgumentException if you initialized the Builder with a URL, which uses
+ * {@link Reader.FileMode#MEMORY}, but you provided a different
+ * FileMode to this method.
+ */
+ public Builder fileMode(Reader.FileMode val) {
+ if (this.stream != null && Reader.FileMode.MEMORY != val) {
+ throw new IllegalArgumentException(
+ "Only FileMode.MEMORY is supported when using an InputStream.");
+ }
+ this.mode = val;
+ return this;
+ }
+
+ /**
+ * @return an instance of {@code DatabaseReader} created from the
+ * fields set on this builder.
+ * @throws IOException if there is an error reading the database
+ */
+ public GalaxyDataBaseReader build() throws IOException {
+ return new GalaxyDataBaseReader(this);
+ }
+ }
+
+
+ /**
+ * @param ipAddress IPv4 or IPv6 address to lookup.
+ * @return A <T> object with the data for the IP address
+ * @throws IOException if there is an error opening or reading from the file.
+ * @throws AddressNotFoundException if the IP address is not in our database
+ */
+ private <T> T get(InetAddress ipAddress, Class<T> cls,
+ String type) throws IOException, AddressNotFoundException {
+
+ String databaseType = this.getMetadata().getDatabaseType();
+ if (!databaseType.contains(type)) {
+ String caller = Thread.currentThread().getStackTrace()[2]
+ .getMethodName();
+ throw new UnsupportedOperationException(
+ "Invalid attempt to open a " + databaseType
+ + " database using the " + caller + " method");
+ }
+
+ ObjectNode node = jsonNodeToObjectNode(reader.get(ipAddress));
+
+ // We throw the same exception as the web service when an IP is not in
+ // the database
+ if (node == null) {
+ throw new AddressNotFoundException("The address "
+ + ipAddress.getHostAddress() + " is not in the database.");
+ }
+
+ InjectableValues inject = new JsonInjector(locales, ipAddress.getHostAddress());
+ return this.om.reader(inject).treeToValue(node, cls);
+ }
+
+ private ObjectNode jsonNodeToObjectNode(JsonNode node)
+ throws InvalidDatabaseException {
+ if (node == null || node instanceof ObjectNode) {
+ return (ObjectNode) node;
+ }
+ throw new InvalidDatabaseException(
+ "Unexpected data type returned. The GeoIP2 database may be corrupt.");
+ }
+
+
+
+ public LocationResponse location(InetAddress ipAddress) throws IOException, GeoIp2Exception {
+ return this.get(ipAddress, LocationResponse.class, "");
+
+ }
+
+
+ public void close() throws IOException {
+ this.reader.close();
+ }
+
+
+ /**
+ * @return the metadata for the open MaxMind DB file.
+ */
+ public Metadata getMetadata() {
+ return this.reader.getMetadata();
+ }
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/IPUtil.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/IPUtil.java
new file mode 100644
index 0000000..6e9c779
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/IPUtil.java
@@ -0,0 +1,766 @@
+package com.mesalab.tool.utils;
+
+
+import com.mesalab.tool.domain.Nets;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.StringWriter;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
+ * <p>对IP进行处理工具类</p>
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2018-08-30
+ *
+ */
+public class IPUtil {
+
+ private static Logger logger = LoggerFactory.getLogger(IPUtil.class);
+ private static byte pos []= new byte []{(byte)128,64,32,16,8,4,2,1};
+ private static final Pattern IPV4Pattern = Pattern.
+ compile("\\b((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\b");
+ private static final Pattern IPV6_STD_PATTERN =
+ Pattern.compile(
+ "^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");
+
+ private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
+ Pattern.compile(
+ "^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");
+
+
+ /**
+ *
+ * <p>将10进制IP转为字符串,网络序。IP((0-255).(0-255).(0-255).(0-255))格式.
+ * ip10为字符串形式能给处理带来方便.
+ * </p>
+ * <pre>
+ * IpUtil.getIpString("3232235777") = "192.168.1.1"
+ * </pre>
+ * @see #getIpDesimal(String)
+ * @param ip10 10进制IP
+ * @return 返回如<code>0.0.0.0</code>格式IP
+ */
+ public static String getIpString(String ip10) {
+ StringBuffer sb = new StringBuffer("");
+ if (ip10.indexOf("-") > -1) {
+
+ Integer intIP = Integer.parseInt(setStrEmpty(ip10));
+
+ sb.append(String.valueOf(intIP&0x000000FF));
+ sb.append(".");
+ sb.append(String.valueOf((intIP&0x0000FFFF)>>>8));
+ sb.append(".");//将高8位置0,然后右移16位
+ sb.append(String.valueOf((intIP&0x00FFFFFF)>>>16));
+ sb.append(".");
+ sb.append(String.valueOf(intIP>>>24&0xFF));//直接右移24位
+ return sb.toString();
+ } else {
+
+ Long longIP = Long.parseLong(setStrEmpty(ip10));
+ sb.append(String.valueOf(longIP&0x000000FF));
+ sb.append(".");
+ sb.append(String.valueOf((longIP&0x0000FFFF)>>>8));
+ sb.append(".");//将高8位置0,然后右移16位
+ sb.append(String.valueOf((longIP&0x00FFFFFF)>>>16));
+ sb.append(".");
+ sb.append(String.valueOf(longIP>>>24&0xFF));//直接右移24位
+ return sb.toString();
+ }
+ }
+
+ /**
+ *
+ * <p>将10进制IP转为字符串,主机序。IP((0-255).(0-255).(0-255).(0-255))格式.
+ * ip10为字符串形式能给处理带来方便.
+ * </p>
+ * <pre>
+ * IpUtil.getIpHostString("3232235777") = "192.168.1.1"
+ * </pre>
+ * @see #getIpDesimal(String)
+ * @param ip10 10进制IP
+ * @return 返回如<code>0.0.0.0</code>格式IP
+ */
+ //将10进制整数形式转换成127.0.0.1形式的IP地址,按网络序
+ public static String getIpHostString(String ip10) {
+ StringBuffer sb = new StringBuffer(32);
+ if (ip10.indexOf("-") > -1) {
+
+ Integer intIP = Integer.parseInt(setStrEmpty(ip10));
+
+ sb.append(String.valueOf(intIP >>> 24));// 直接右移24位
+ sb.append(".");
+ sb.append(String.valueOf((intIP & 0x00FFFFFF) >>> 16)); // 将高8位置0,然后右移16位
+ sb.append(".");
+ sb.append(String.valueOf((intIP & 0x0000FFFF) >>> 8));
+ sb.append(".");
+ sb.append(String.valueOf(intIP & 0x000000FF));
+ return sb.toString();
+ } else {
+ Long longIP = Long.parseLong(setStrEmpty(ip10));
+
+ sb.append(String.valueOf(longIP >>> 24));// 直接右移24位
+ sb.append(".");
+ sb.append(String.valueOf((longIP & 0x00FFFFFF) >>> 16)); // 将高8位置0,然后右移16位
+ sb.append(".");
+ sb.append(String.valueOf((longIP & 0x0000FFFF) >>> 8));
+ sb.append(".");
+ sb.append(String.valueOf(longIP & 0x000000FF));
+
+ return sb.toString();
+ }
+ }
+
+
+ /**
+ * 判断一个IP地址是否属于某一个子网
+ *
+ * @param ip IP地址
+ * @param prefix 子网地址
+ * @param prefixLen 掩码长度
+ * @return true or false
+ */
+ public static boolean inPrefix(String ip, String prefix, int prefixLen) {
+ String binPrefix = toBinaryString(prefix);
+ if (binPrefix.length() > prefixLen) {
+ binPrefix = binPrefix.substring(0,prefixLen);
+ }
+ String binIP = toBinaryString(ip);
+ binIP = binIP.substring(0,prefixLen);
+ if (binIP.equals(binPrefix)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+ /**
+ * 获得两个IP间的范围,如192.168.0.128-192.168.2.256。
+ * 注意:本方法不做合法性检查!
+ *
+ * @param startIp 起始IP
+ * @param endIp 中止IP
+ * @return 范围内的IP地址数组
+ */
+ public static List<String> getIPRange(String startIp, String endIp) {
+
+ List<String> list = new ArrayList<String>();
+
+ try{
+
+ long start = getIpHostDesimal(startIp);
+ long end = getIpHostDesimal(endIp);
+
+ for (long i = start; i <= end; i++) {
+ list.add(getIpHostString(String.valueOf(i)));
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return list;
+ }
+
+
+
+ /**
+ * 验证IP为保留三个IP区域私有地址
+ * @param ip IPV4
+ * @return boolean true 私有地址 false 公有地址
+ */
+ public static boolean internalIp(String ip) {
+ byte[] addr = getAddress(ip);
+ return internalIp(addr);
+ }
+
+ private static boolean internalIp(byte[] addr) {
+ final byte b0 = addr[0];
+ final byte b1 = addr[1];
+ //10.x.x.x/8
+ final byte SECTION_1 = 0x0A;
+ //172.16.x.x/12
+ final byte SECTION_2 = (byte) 0xAC;
+ final byte SECTION_3 = (byte) 0x10;
+ final byte SECTION_4 = (byte) 0x1F;
+ //192.168.x.x/16
+ final byte SECTION_5 = (byte) 0xC0;
+ final byte SECTION_6 = (byte) 0xA8;
+ switch (b0) {
+ case SECTION_1:
+ return true;
+ case SECTION_2:
+ if (b1 >= SECTION_3 && b1 <= SECTION_4) {
+ return true;
+ }
+ case SECTION_5:
+ switch (b1) {
+ case SECTION_6:
+ return true;
+ }
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * 获得子网的所有IP地址;如:192.168.0.1/24。
+ * 注意:本方法不做合法性检查!
+ * @param prefix 子网所属IP地址
+ * @param prefixLen 子网掩码
+ * @return List<String>
+ */
+ public static List<String> getIPRange(String prefix, int prefixLen) {
+ String binPrefix = toBinaryString(prefix);
+ if (binPrefix.length() > prefixLen) {
+ binPrefix = binPrefix.substring(0,prefixLen);
+ }
+ StringBuffer ip1 = new StringBuffer(binPrefix);
+ StringBuffer ip2 = new StringBuffer(binPrefix);
+ for (int i = ip1.length(); i < 32; i++) {
+ ip1.append('0');
+ }
+ for (int i = ip2.length(); i < 32; i++) {
+ ip2.append('1');
+ }
+
+ return getIPRange(toIPString(ip1.toString()),toIPString(ip2.toString()));
+ }
+
+
+ /**
+ *
+ * <p>根据标准ip段获取,该段子网掩码
+ * </p>
+ * @param startIP 起始ip,endIP 结束ip
+ * @return 返回如<code>子网掩码</code>格式IP
+ */
+ public static String getMask(String startIP,String endIP) {
+ byte start [] = getAddress(startIP);
+ byte end [] = getAddress(endIP);
+ byte mask [] = new byte [start.length];
+ boolean flag=false;
+ for(int i=0; i<start.length; i++){
+
+ mask[i]=(byte)~(start[i]^end[i]);
+
+ if (flag) {
+ mask[i]=0;
+ }
+ if(mask[i]!=-1){
+ mask[i]=getMask(mask[i]);
+ flag=true;
+ }
+ }
+ return toString(mask);
+ }
+
+
+
+ private static byte getMask(byte b) {
+ if (b==0) {
+ return b;
+ }
+ byte p = pos[0];
+ for(int i=0;i<8;i++){
+ if ((b&pos[i])==0) {
+ break;
+ }
+ p=(byte)(p>>1);
+ }
+ p=(byte)(p<<1);
+ return (byte)(b&p);
+ }
+
+
+ private static byte[] getAddress(String address) {
+ String subStr [] = address.split("\\.");
+ if(subStr.length!=4) {
+ throw new IllegalArgumentException("所传入的IP地址不符合IPv4的规范");
+ }
+ byte b [] = new byte [4];
+ for (int i=0;i<b.length;i++) {
+ b [i]=(byte)Integer.parseInt(subStr[i]);
+ }
+ return b;
+ }
+
+
+ /**
+ * 将IPv4形式掩码形式转为,整型掩码位数
+ * @param netmarks
+ * @return
+ */
+ public static int getNetMask(String netmarks)
+ {
+ if(!isMask(netmarks)){
+ throw(new RuntimeException("掩码格式错误!"));
+ }
+ StringBuffer sbf;
+ String str;
+ int inetmask=0,count=0;
+ String[] ipList=netmarks.split("\\.");
+ for(int n=0;n<ipList.length;n++)
+ {
+ sbf = toBin(Integer.parseInt(ipList[n]));
+ str=sbf.reverse().toString();
+ count=0;
+ for(int i=0;i<str.length();i++){
+ i=str.indexOf('1',i);
+ if(i==-1){break;}
+ count++;
+ }
+ inetmask+=count;
+ }
+ return inetmask;
+ }
+
+ /**
+ * 计算子网大小
+ * @param netmask
+ * @return
+ */
+ public static int getPoolMax(int netmask)
+ {
+ if(netmask<=0||netmask>=32)
+ {
+ return 0;
+ }
+ int bits=32-netmask;
+ return (int) Math.pow(2,bits) -2;
+ }
+
+ private static StringBuffer toBin(int x)
+ {
+ StringBuffer result=new StringBuffer();
+ result.append(x%2);
+ x/=2;
+ while(x>0){
+ result.append(x%2);
+ x/=2;
+ }
+ return result;
+ }
+
+
+
+
+
+ /**
+ * 根据起始IP地址和子网掩码计算终止IP
+ * @return String 子网的结束IP
+ */
+ public static String getEndIP(String StartIP,int netmask)
+ {
+ return getEndIP(StartIP,convertMask(netmask));
+ }
+ /**
+ * 根据起始IP地址和子网掩码计算终止IP
+ * @return String 子网的结束IP
+ */
+ public static String getEndIP(String StartIP, String netmask)
+ {
+ Nets nets = new Nets();
+ String[] start=Negation(StartIP,netmask).split("\\.");
+ nets.setStartIP(start[0]+"."+start[1]+"."+start[2]+"."+(Integer.valueOf(start[3])+1));
+ nets.setEndIP(TaskOR(Negation(StartIP,netmask),netmask));
+ nets.setNetMask(netmask);
+ return nets.getEndIP();
+ }
+
+ /**
+ * temp1根据temp2取反
+ */
+ private static String Negation(String StartIP,String netmask)
+ {
+ String[] temp1=StartIP.trim().split("\\.");
+ String[] temp2=netmask.trim().split("\\.");
+ int[] rets=new int[4];
+ for (int i =0;i<4;i++) {
+ rets[i]=Integer.parseInt(temp1[i])&Integer.parseInt(temp2[i]);
+ }
+ return rets[0]+"."+rets[1]+"."+rets[2]+"."+rets[3];
+ }
+ /**
+ * temp1根据temp2取或
+ */
+ private static String TaskOR(String StartIP,String netmask)
+ {
+ String[] temp1=StartIP.trim().split("\\.");
+ String[] temp2=netmask.trim().split("\\.");
+ int[] rets=new int[4];
+ for (int i =0;i<4;i++) {
+ rets[i]=255-(Integer.parseInt(temp1[i])^Integer.parseInt(temp2[i]));
+ }
+ //return rets[0]+"."+rets[1]+"."+rets[2]+"."+(rets[3]-1);
+ return rets[0]+"."+rets[1]+"."+rets[2]+"."+(rets[3]);
+ }
+
+
+
+ /**
+ * <p>将整型的掩码转换成IPv4型(30 -> 255.255.255.252).</p>
+ *
+ * @param mask 整型掩码.
+ * @return IPv4型掩码.
+ * @exception RuntimeException 掩码错误.
+ */
+ public static String convertMask(int mask) {
+ if (mask > 32 || mask < 8) {
+ throw(new RuntimeException("掩码错误!应为8-32的整数。"));
+ }
+ return toIPString(maskToBinaryString(mask));
+ }
+
+
+ /**
+ * <p>将整型的掩码转换成反向IPv4型(30 -> 255.255.255.252).</p>
+ *
+ * @param mask 整型掩码.
+ * @return IPv4型反向掩码.
+ * @exception Exception 掩码错误.
+ */
+ public static String convertReverseMask(int mask) throws Exception {
+ if (mask > 32 || mask < 8) {
+ throw(new Exception("掩码错误!应为8-32的整数。"));
+ }
+ return toIPString(reverseMaskToBinaryString(mask));
+ }
+
+
+
+ /**
+ * 将整型掩码转换成二进制字符串
+ * @param mask 整型掩码
+ * @return 二进制型掩码.
+ */
+ private static String maskToBinaryString(int mask) {
+ StringBuffer str = new StringBuffer();
+
+ for(int i=1;i<=32;i++) {
+ if (i <= mask) {
+ str.append('1');
+ } else {
+ str.append('0');
+ }
+ }
+ return str.toString();
+ }
+
+
+ /**
+ * 将整型掩码转换成二进制字符串
+ * @param mask 整型掩码
+ * @return 反向二进制型掩码.
+ */
+ private static String reverseMaskToBinaryString(int mask) {
+ StringBuffer str = new StringBuffer();
+
+ for(int i=1;i<=32;i++) {
+ if (i <= mask) {
+ str.append('0');
+ } else {
+ str.append('1');
+ }
+ }
+ return str.toString();
+ }
+
+
+ /**
+ * 将二进制字符串转换成IPv4型字符串
+ * @param binary 二进制字符串
+ * @return IPv4型IP.
+ */
+ private static String toIPString(String binary) {
+ if (binary.length() < 32) {
+ for (int i=binary.length();i<32;i++) {
+ binary = "0" + binary;
+ }
+ }
+
+ String part1 = binary.substring(0,8);
+ String part2 = binary.substring(8,16);
+ String part3 = binary.substring(16,24);
+ String part4 = binary.substring(24);
+ return Integer.parseInt(part1,2) + "."
+ + Integer.parseInt(part2,2) + "."
+ + Integer.parseInt(part3,2) + "."
+ + Integer.parseInt(part4,2);
+ }
+ /**
+ * 获取子网的网络地址.
+ *
+ * @param ip IP地址.
+ * @param mask 掩码.
+ * @return 网络地址.
+ * @exception Exception IP地址错误或掩码错误.
+ */
+ public static String getSubNetIP(String ip, int mask) throws Exception {
+ if (!isIP(ip)) {
+ throw(new Exception("IP地址不合法!"));
+ }
+ String s1 = toBinaryString(ip);
+ String s2 = maskToBinaryString(mask);
+ return toIPString(Long.toBinaryString(Long.parseLong(s1,2)&Long.parseLong(s2,2)));
+ }
+
+ /**
+ * <p>将整型掩码转换成IPv4型的反码(30 -> 0.0.0.3).</p>
+ *
+ * @param mask 整型掩码.
+ * @return IPv4型反码.
+ * @exception Exception 掩码错误.
+ */
+ public static String reverseMask(int mask) throws Exception {
+ if (mask > 32 || mask < 8) {
+ throw(new Exception("掩码错误!应为8-32的整数。"));
+ }
+ String str = maskToBinaryString(mask);
+ str = str.replace('0','2');
+ str = str.replace('1','0');
+ str = str.replace('2','1');
+ return toIPString(str);
+ }
+
+ /**
+ * 将IPv4型字符串转换成长度为32的二进制字符串
+ * 需要加验证是否为IP
+ */
+ public static String toBinaryString(String ip) {
+ String[] array = ip.split("[.]");
+ String str = "";
+ for (int i=0; i<array.length; i++) {
+ String s = Integer.toBinaryString(Integer.parseInt(array[i]));
+ if (s.length() < 8) {
+ for (int j=s.length();j<8;j++) {
+ s = "0" + s;
+ }
+ }
+ str += s;
+ }
+ return str;
+ }
+
+
+ /**
+ *
+ * <p>验证Ip是否符合规则.给定字符串,判断是否符合正则验证的ip格式.</p>
+ * <pre>例子说明:</pre>
+ * @param ip ip字符
+ * @return <code>true</code> ip符合验证规则, <code>false</code> ip不符合验证规则.
+ */
+ public static boolean isIP(String ip) {
+ if (ip == null) {
+ return false;
+ }
+ Matcher mat = IPV4Pattern.matcher(ip);
+ return mat.matches();
+ }
+
+
+ public static boolean isIPv6StdAddress(final String input) {
+ return IPV6_STD_PATTERN.matcher(input).matches();
+ }
+
+ public static boolean isIPv6HexCompressedAddress(final String input) {
+ return IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
+ }
+
+ public static boolean isIPv6Address(final String input) {
+ return isIPv6StdAddress(input) || isIPv6HexCompressedAddress(input);
+ }
+
+ /**
+ *
+ * <p>在web方式下获取客户端IP地址.</p>
+ * <p>
+ * 使用该方法,需要在有javaee.jar扩展包前提下.
+ * </p>
+ * @param request HttpServletRequest请求对象
+ * @return 返回字符串IP地址
+ */
+ public static String getIpAddr(HttpServletRequest request) {
+ String ip = request.getHeader("X-Forwarded-For");
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("HTTP_CLIENT_IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getRemoteAddr();
+ }
+ return ip;
+ }
+
+
+ /**
+ *
+ * <p>验证mask是否符合规则.给定字符串,判断是否符合正则验证的mask格式.</p>
+ * <pre>例子说明:</pre>
+ * @param mask mask字符
+ * @return <code>true</code> mask符合验证规则, <code>false</code> mask不符合验证规则.
+ */
+ public static boolean isMask(String mask) {
+ if (mask == null) {
+ return false;
+ }
+ if(!isIP(mask)){
+ return false;
+ }
+ String[] ips = mask.split("\\.");
+ String binaryVal = "";
+ for (int i = 0; i < ips.length; i++)
+ {
+ String binaryStr = Integer.toBinaryString(Integer.parseInt(ips[i]));
+ Integer times = 8 - binaryStr.length();
+
+ for(int j = 0; j < times; j++)
+ {
+ binaryStr = "0" + binaryStr;
+ }
+ binaryVal += binaryStr;
+ }
+ if(binaryVal.indexOf("01")!=-1){
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ *
+ * <p>将IP进制转换成十进制网络字节序</p>
+ * <p>
+ * IP是一个字符串,符合IP的规则(0-255).(0-255).(0-255).(0-255).
+ * 将ip转换成长整型的原因是:处理时间类型简单;入库节省空间,查询提高效率.
+ * </p>
+ * <pre>
+ * IpUtil.getIpDesimal("192.168.1.1") = 3232235777
+ * IpUtil.getIpDesimal("192.168.1.256") = -1 //不符合Ip规则
+ * </pre>
+ * @see #getIpString(String)
+ * @param ip 符合IP规则的字符串
+ * @return <code>-1</code> 验证ip不合法,<code>ip</code> 计算ip返回长整型.
+ */
+ public static long getIpDesimal(String ip) {
+ long ip10 = 0;
+ if (!isIP(ip)) {
+ return -1; // ip 不合法
+ }
+ String[] ss = ip.trim().split("\\.");
+ for (int i = 0; i < 4; i++) {
+ ip10 += Math.pow(256, i) * Long.parseLong(ss[i]);
+ }
+
+ return ip10;
+ }
+
+
+ /**
+ *
+ * <p>将IP进制转换成十进制主机字节序</p>
+ * <p>
+ * IP是一个字符串,符合IP的规则(0-255).(0-255).(0-255).(0-255).
+ * 将ip转换成长整型的原因是:处理时间类型简单;入库节省空间,查询提高效率.
+ * </p>
+ * <pre>
+ * IpUtil.getIpHostDesimal("192.168.1.1") = 3232235777
+ * IpUtil.getIpHostDesimal("192.168.1.256") = -1 //不符合Ip规则
+ * </pre>
+ * @see #getIpString(String)
+ * @param ip 符合IP规则的字符串
+ * @return <code>-1</code> 验证ip不合法,<code>ip</code> 计算ip返回长整型.
+ */
+
+ public static long getIpHostDesimal(String ip) {
+ long ip10 = 0;
+ if (!isIP(ip)) {
+ return -1; // ip 不合法
+ }
+ String[] ss = ip.trim().split("\\.");
+ for (int i = 0; i < 4; i++) {
+ ip10 += Math.pow(256, 3 - i) * Long.parseLong(ss[i]);
+ }
+
+ return ip10;
+ }
+
+
+
+ /**
+ *
+ * <p>获取IP/mask 包含IP数量,适合完整IPw网段</p>
+ * <p>
+ *
+ *
+ * </p>
+ * <pre>
+ *
+ *
+ * </pre>
+ * @param ip 符合IP规则的字符串
+ * @param mask 掩码格式
+ * @return <code>-1</code> 验证ip不合法,<code>ip</code> 计算ip返回长整型.
+ */
+ public static long getIpNum(String ip, int mask) {
+ long num = 0;
+
+ if (isIP(ip)) {
+ String endIp = getEndIP(ip, mask);
+ num = getIpHostDesimal(endIp) - getIpHostDesimal(ip) +1;
+
+ } else {
+ throw new IllegalArgumentException("所传入的IP地址不符合IPV4规范");
+ }
+
+ return num;
+ }
+
+
+
+
+ // 此方法用于判断数据为空就置为0
+ private static String setStrEmpty(String str) {
+ if ("".equals(str) || str == null) {
+ str = "0";
+ }
+ return str;
+ }
+
+
+ private static String toString(byte[] address) {
+ StringWriter sw = new StringWriter(16);
+ sw.write(Integer.toString(address[0]&0xFF));
+ for(int i=1;i<address.length;i++){
+ sw.write(".");
+ sw.write(Integer.toString(address[i]&0xFF));
+ }
+ return sw.toString();
+ }
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/IpLookup.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/IpLookup.java
new file mode 100644
index 0000000..757cf0a
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/IpLookup.java
@@ -0,0 +1,682 @@
+package com.mesalab.tool.utils;
+
+import com.google.common.base.Joiner;
+import com.maxmind.db.CHMCache;
+import com.maxmind.geoip2.exception.AddressNotFoundException;
+import com.mesalab.tool.domain.LocationResponse;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URL;
+
+/**
+ * @ClassName IpLookup
+ * @Description 对IP定位查找工具类
+ * @Author 中电积至有限公司 darnell
+ * @Date 2020-05-8 20:01
+ * @Version 1.0.2
+ **/
+public final class IpLookup extends AbstractIpLookup{
+
+ enum ServiceEnum {
+ PRIVATE, PUBLIC
+ }
+ public final static String DEFAULT_DATABASE_PATH = "dat";
+ private final static String SEPRATOR = ",";
+ private final static String DEFAULT_DB_IP_PUBLIC = "ip.mmdb";
+ private final static String DEFAULT_DB_IP_PUBLIC_V4 = "ip_v4.mmdb";
+ private final static String DEFAULT_DB_IP_PUBLIC_V6 = "ip_v6.mmdb";
+ private final static String DEFAULT_DB_IP_PRIVATE = "ip_private.mmdb";
+ private final static String DEFAULT_DB_IP_PRIVATE_V4 = "ip_private_v4.mmdb";
+ private final static String DEFAULT_DB_IP_PRIVATE_V6 = "ip_private_v6.mmdb";
+
+ private AsnLookup asnLookup;
+
+
+ private static GalaxyDataBaseReader ipLocationPublicReader;
+ private static GalaxyDataBaseReader ipLocationPublicReaderV4;
+ private static GalaxyDataBaseReader ipLocationPublicReaderV6;
+
+
+ private static GalaxyDataBaseReader ipLocationPrivateReader;
+ private static GalaxyDataBaseReader ipLocationPrivateReaderV4;
+ private static GalaxyDataBaseReader ipLocationPrivateReaderV6;
+
+
+
+ synchronized void init(Builder builder) {
+ try {
+
+ if (builder.isDefaultDB) {
+
+ File dbPublicFile = new File(System.getProperty("user.dir") + File.separator + DEFAULT_DATABASE_PATH + File.separator
+ + DEFAULT_DB_IP_PUBLIC);
+
+ if (!dbPublicFile.exists()) {
+ URL url = IpLookup.class.getResource("/"+ DEFAULT_DATABASE_PATH + "/" + DEFAULT_DB_IP_PUBLIC);
+ if (url != null) {
+ dbPublicFile = new File(url.getPath());
+ }
+ }
+
+ File dbPublicV4File = new File(System.getProperty("user.dir") + File.separator + DEFAULT_DATABASE_PATH + File.separator
+ + DEFAULT_DB_IP_PUBLIC_V4);
+
+ if (!dbPublicV4File.exists()) {
+ URL url = IpLookup.class.getResource("/"+ DEFAULT_DATABASE_PATH + "/" + DEFAULT_DB_IP_PUBLIC_V4);
+ if (url != null) {
+ dbPublicV4File = new File(url.getPath());
+ }
+ }
+
+ File dbPublicV6File = new File(System.getProperty("user.dir") + File.separator + DEFAULT_DATABASE_PATH + File.separator
+ + DEFAULT_DB_IP_PUBLIC_V6);
+ if (!dbPublicV6File.exists()) {
+ URL url = IpLookup.class.getResource("/"+ DEFAULT_DATABASE_PATH + "/" + DEFAULT_DB_IP_PUBLIC_V6);
+ if (url != null) {
+ dbPublicV6File = new File(url.getPath());
+ }
+ }
+
+ File dbPrivateFile = new File(System.getProperty("user.dir") + File.separator + DEFAULT_DATABASE_PATH + File.separator
+ +DEFAULT_DB_IP_PRIVATE);
+
+ if (!dbPrivateFile.exists()) {
+ URL url = IpLookup.class.getResource("/"+ DEFAULT_DATABASE_PATH + "/" + DEFAULT_DB_IP_PRIVATE);
+ if (url != null) {
+ dbPrivateFile = new File(url.getPath());
+ }
+ }
+
+
+ File dbPrivateV4File = new File(System.getProperty("user.dir") + File.separator + DEFAULT_DATABASE_PATH + File.separator
+ + DEFAULT_DB_IP_PRIVATE_V4);
+
+ if (!dbPrivateV4File.exists()) {
+ URL url = IpLookup.class.getResource("/"+ DEFAULT_DATABASE_PATH + "/" + DEFAULT_DB_IP_PRIVATE_V4);
+ if (url != null) {
+ dbPrivateV4File = new File(url.getPath());
+ }
+ }
+
+ File dbPrivateV6File = new File(System.getProperty("user.dir") + File.separator + DEFAULT_DATABASE_PATH + File.separator
+ + DEFAULT_DB_IP_PRIVATE_V6);
+ if (!dbPrivateV6File.exists()) {
+ URL url = IpLookup.class.getResource("/"+ DEFAULT_DATABASE_PATH + "/" + DEFAULT_DB_IP_PRIVATE_V6);
+ if (url != null) {
+ dbPrivateV6File = new File(url.getPath());
+ }
+ }
+
+ if (dbPublicFile.exists()) {
+ ipLocationPublicReader = new GalaxyDataBaseReader.Builder(dbPublicFile).withCache(new CHMCache()).build();
+ }
+ if (dbPublicV4File.exists()) {
+ ipLocationPublicReaderV4 = new GalaxyDataBaseReader.Builder(dbPublicV4File).withCache(new CHMCache()).build();
+ }
+
+ if (dbPublicV6File.exists()) {
+ ipLocationPublicReaderV6 = new GalaxyDataBaseReader.Builder(dbPublicV6File).withCache(new CHMCache()).build();
+ }
+
+ if (dbPrivateFile.exists()) {
+ ipLocationPrivateReader = new GalaxyDataBaseReader.Builder(dbPrivateFile).withCache(new CHMCache()).build();
+ }
+
+ if (dbPrivateV4File.exists()) {
+ ipLocationPrivateReaderV4 = new GalaxyDataBaseReader.Builder(dbPrivateV4File).withCache(new CHMCache()).build();
+ }
+
+ if (dbPrivateV6File.exists()) {
+ ipLocationPrivateReaderV6 = new GalaxyDataBaseReader.Builder(dbPrivateV6File).withCache(new CHMCache()).build();
+ }
+
+
+ asnLookup = new AsnLookup.Builder(true).build();
+
+ } else {
+
+
+ if (StringUtil.isNotBlank(builder.ipDatabasePublicFile)) {
+ ipLocationPublicReader = new GalaxyDataBaseReader.Builder(new File(builder.ipDatabasePublicFile))
+ .withCache(new CHMCache()).build();
+ }
+
+ if (StringUtil.isNotBlank(builder.ipDatabasePublicFileV4)) {
+ ipLocationPublicReaderV4 = new GalaxyDataBaseReader.Builder(new File(builder.ipDatabasePublicFileV4))
+ .withCache(new CHMCache()).build();
+ }
+
+ if (StringUtil.isNotBlank(builder.ipDatabasePublicFileV6)) {
+ ipLocationPublicReaderV6 = new GalaxyDataBaseReader.Builder(new File(builder.ipDatabasePublicFileV6))
+ .withCache(new CHMCache()).build();
+ }
+
+ if (StringUtil.isNotBlank(builder.ipDatabasePrivateFile)) {
+ ipLocationPrivateReader = new GalaxyDataBaseReader.Builder(new File(builder.ipDatabasePrivateFile))
+ .withCache(new CHMCache()).build();
+ }
+
+ if (StringUtil.isNotBlank(builder.ipDatabasePrivateFileV4)) {
+ ipLocationPrivateReaderV4 = new GalaxyDataBaseReader.Builder(new File(builder.ipDatabasePrivateFileV4))
+ .withCache(new CHMCache()).build();
+ }
+
+ if (StringUtil.isNotBlank(builder.ipDatabasePrivateFileV6)) {
+ ipLocationPrivateReaderV6 = new GalaxyDataBaseReader.Builder(new File(builder.ipDatabasePrivateFileV6))
+ .withCache(new CHMCache()).build();
+ }
+
+
+ asnLookup = new AsnLookup.Builder(false)
+ .loadDataFile(builder.asnDatabasePublicFile)
+ .loadDataFileV4(builder.asnDatabasePublicFileV4)
+ .loadDataFileV6(builder.asnDatabasePublicFileV6)
+ .loadDataFilePrivate(builder.asnDatabasePrivateFile)
+ .loadDataFilePrivateV4(builder.asnDatabasePrivateFileV4)
+ .loadDataFilePrivateV6(builder.asnDatabasePrivateFileV6)
+ .build();
+
+
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ logger.warn("Unknow mmdb dat file , please check your dat path!");
+
+ }
+
+
+ }
+
+
+ private IpLookup(Builder builder) {
+ init(builder);
+ }
+
+
+
+ /**
+ * 加载mmdb数据字典文件,内部生成mmdb动态库。
+ *
+ * 1.默认记载IP库,使用方式如下:
+ * IpLookup ipLookup = new IpLookup.Builder(true).build();
+ * 自动加载应用dat目录下的库文件,命名为:all_ip_info_v4.mmdb与all_ip_info_v6.mmdb库。
+ *
+ * 2.手动加载IP库,使用方式如下:
+ * <p>
+ * IpLookup ipLookup = new IpLookup.Builder(false).loadDataFileV4("D:\\galaxy-tool\\dat\\ip.mmdb").
+ * loadDataFileV6("D:\\galaxy-tool\\dat\\all_ip_info_v6.mmdb").build();
+ *
+ * </p>
+ */
+ public static final class Builder {
+ String ipDatabasePublicFile;
+ String ipDatabasePublicFileV4;
+ String ipDatabasePublicFileV6;
+
+ String ipDatabasePrivateFile;
+ String ipDatabasePrivateFileV4;
+ String ipDatabasePrivateFileV6;
+
+ String asnDatabasePublicFile;
+ String asnDatabasePublicFileV4;
+ String asnDatabasePublicFileV6;
+
+ String asnDatabasePrivateFile;
+ String asnDatabasePrivateFileV4;
+ String asnDatabasePrivateFileV6;
+
+ boolean isDefaultDB;
+
+ /**
+ *
+ * @param isDefaultDB <code>false</code> 手动指定IP库路径 <code>true</code> 使用默认路径
+ */
+ public Builder(boolean isDefaultDB) {
+ this.isDefaultDB = isDefaultDB;
+ }
+
+ /**
+ *
+ * @param ipDatabasePublicFile 加载IPv4与IPV6 mmdb库文件
+ * @return
+ */
+ public Builder loadDataFile(String ipDatabasePublicFile) {
+ this.ipDatabasePublicFile = ipDatabasePublicFile;
+ return this;
+ }
+
+ /**
+ *
+ * @param ipDatabasePublicFileV4 加载IPv4 mmdb库文件
+ * @return
+ */
+ public Builder loadDataFileV4(String ipDatabasePublicFileV4) {
+ this.ipDatabasePublicFileV4 = ipDatabasePublicFileV4;
+ return this;
+ }
+
+ /**
+ *
+ * @param ipDatabasePublicFileV6 加载IPv6 mmdb库文件
+ * @return
+ */
+ public Builder loadDataFileV6(String ipDatabasePublicFileV6) {
+ this.ipDatabasePublicFileV6 = ipDatabasePublicFileV6;
+ return this;
+ }
+
+ /**
+ *
+ * @param ipDatabasePrivateFile 加载用户自定义IPv4与IPv6 mmdb库文件
+ * @return
+ */
+ public Builder loadDataFilePrivate(String ipDatabasePrivateFile) {
+ this.ipDatabasePrivateFile = ipDatabasePrivateFile;
+ return this;
+ }
+
+ /**
+ *
+ * @param ipDatabasePrivateFileV4 加载用户自定义IPv4 mmdb库文件
+ * @return
+ */
+ public Builder loadDataFilePrivateV4(String ipDatabasePrivateFileV4) {
+ this.ipDatabasePrivateFileV4 = ipDatabasePrivateFileV4;
+ return this;
+ }
+
+ /**
+ *
+ * @param ipDatabasePrivateFileV6 加载用户自定义IPv6 mmdb库文件
+ * @return
+ */
+ public Builder loadDataFilePrivateV6(String ipDatabasePrivateFileV6) {
+ this.ipDatabasePrivateFileV6 = ipDatabasePrivateFileV6;
+ return this;
+ }
+
+
+
+ /**
+ *
+ * @param asnDatabasePublicFile 加载asn IPv4与IPv6库
+ * @return
+ */
+ public Builder loadAsnDataFile(String asnDatabasePublicFile) {
+ this.asnDatabasePublicFile = asnDatabasePublicFile;
+ return this;
+ }
+
+
+ /**
+ *
+ * @param asnDatabasePublicFileV4 加载asn IPv4 mmdb库文件
+ * @return
+ */
+ public Builder loadAsnDataFileV4(String asnDatabasePublicFileV4) {
+ this.asnDatabasePublicFileV4 = asnDatabasePublicFileV4;
+ return this;
+ }
+
+
+ /**
+ *
+ * @param asnDatabasePublicFileV6 加载asn IPv6 mmdb库文件
+ * @return
+ */
+ public Builder loadAsnDataFileV6(String asnDatabasePublicFileV6) {
+ this.asnDatabasePublicFileV6 = asnDatabasePublicFileV6;
+ return this;
+ }
+
+
+ /**
+ *
+ * @param asnDatabasePrivateFile 加载asn用户自定义 IPv4与IPv6库
+ * @return
+ */
+ public Builder loadAsnDataFilePrivate(String asnDatabasePrivateFile) {
+ this.asnDatabasePrivateFile = asnDatabasePrivateFile;
+ return this;
+ }
+
+ /**
+ *
+ * @param asnDatabasePrivateFileV4 加载asn用户自定义 IPv4 mmdb库文件
+ * @return
+ */
+ public Builder loadAsnDataFilePrivateV4(String asnDatabasePrivateFileV4) {
+ this.asnDatabasePrivateFileV4 = asnDatabasePrivateFileV4;
+ return this;
+ }
+
+
+
+ /**
+ *
+ * @param asnDatabasePrivateFileV6 加载用户自定义asn IPv6 mmdb库文件
+ * @return
+ */
+ public Builder loadAsnDataFilePrivateV6(String asnDatabasePrivateFileV6) {
+ this.asnDatabasePrivateFileV6 = asnDatabasePrivateFileV6;
+ return this;
+ }
+
+ /**
+ * 构建对象
+ * @return
+ * @throws IOException
+ */
+ public IpLookup build() {
+ return new IpLookup(this);
+ }
+
+ }
+
+ @Override
+ public String countryLookup(String ip) {
+ String result = "";
+
+ LocationResponse response = getResponse(ip);
+
+ if (StringUtil.isNotEmpty(response)) {
+ result = StringUtil.setDefaultIfEmpty(response.getCountry(), "").toString() ;
+ }
+
+ return StringUtil.setDefaultIfEmpty(result, UNKNOW).toString();
+ }
+
+ @Override
+ public String cityLookupDetail(String ip) {
+
+ String result = "";
+ LocationResponse response = getResponse(ip);
+ if (StringUtil.isNotEmpty(response)) {
+ result = Joiner.on(SEPRATOR).skipNulls().join(response.getCity(), response.getProvince(), response.getCountry());
+ }
+
+ return StringUtil.setDefaultIfEmpty(result, UNKNOW).toString();
+ }
+
+ @Override
+ public String cityLookup(String ip) {
+ String result = "";
+ LocationResponse response = getResponse(ip);
+
+ if (StringUtil.isNotEmpty(response)) {
+ if(StringUtil.isNotBlank(response.getCity())) {
+ result = response.getCity();
+ }
+ }
+
+ return StringUtil.setDefaultIfEmpty(result, UNKNOW).toString();
+
+ }
+
+ @Override
+ public String provinceLookup(String ip) {
+ String result = "";
+ LocationResponse response = getResponse(ip);
+ if (StringUtil.isNotEmpty(response)) {
+ if (StringUtil.isNotBlank(response.getProvince())) {
+ result = response.getProvince();
+ }
+ }
+
+ return StringUtil.setDefaultIfEmpty(result, UNKNOW).toString();
+ }
+
+
+ @Override
+ public String latLngLookup(String ip) {
+
+ String result = "";
+ try {
+ LocationResponse response = getResponse(ip);
+ if (StringUtil.isNotEmpty(response)
+ && StringUtil.isNotBlank(response.getLatitude())
+ && StringUtil.isNotBlank(response.getLongitude())) {
+
+
+ result = Joiner.on(SEPRATOR).skipNulls().join(response.getLatitude(), response.getLongitude());
+
+ } else {
+ result = Joiner.on(SEPRATOR).join(UNKNOW, UNKNOW);
+ }
+
+ } catch (Exception e) {
+
+ throw new IllegalArgumentException("ip address :" + ip +", parser error " + e);
+ }
+
+ return result;
+
+ }
+
+
+ @Override
+ public String cityLatLngLookup(String ip) {
+ String result = "";
+ try {
+
+ result = Joiner.on(SEPRATOR).skipNulls().join(cityLookup(ip), latLngLookup(ip));
+
+ } catch (Exception e) {
+
+ throw new IllegalArgumentException("ip address :" + ip +", parser error " + e);
+ }
+
+
+ return StringUtil.setDefaultIfEmpty(result, UNKNOW).toString();
+
+ }
+
+ @Override
+ public String asnLookup(String ip) {
+ return asnLookup.asnLookup(ip);
+
+ }
+
+
+ @Override
+ public String asnLookupInfo(String ip) {
+ return asnLookup.asnLookupInfo(ip);
+ }
+
+ @Override
+ public String asnLookupDetail(String ip) {
+
+ return asnLookup.asnLookupDetail(ip);
+
+
+ }
+
+ private LocationResponse getResponse(String ip) {
+
+ LocationResponse response = null;
+
+ if (!IPUtil.isIP(ip) && !IPUtil.isIPv6Address(ip)) {
+ throw new IllegalArgumentException("unknown ip format :" + ip );
+ }
+
+ response = new Context(new PrivateReader()).executeStragey(ip);
+
+ if (StringUtil.isEmpty(response)) {
+ response = new Context(new PublicReader()).executeStragey(ip);
+ }
+
+ if (StringUtil.isEmpty(response)) {
+ response = new Context(new InnerReader()).executeStragey(ip);
+ }
+
+ return response;
+ }
+
+
+
+
+
+ private GalaxyDataBaseReader getIpDataBaseReaderV4(String service) {
+
+ if (service.equalsIgnoreCase(ServiceEnum.PRIVATE.name())) {
+ if (StringUtil.isNotEmpty(ipLocationPrivateReaderV4)) {
+ return ipLocationPrivateReaderV4;
+ } else {
+ return ipLocationPrivateReader;
+ }
+ } else {
+ if (StringUtil.isNotEmpty(ipLocationPublicReaderV4)) {
+ return ipLocationPublicReaderV4;
+ } else {
+ return ipLocationPublicReader;
+ }
+ }
+
+ }
+
+ private GalaxyDataBaseReader getIpDataBaseReaderV6(String service) {
+
+ if (service.equalsIgnoreCase(ServiceEnum.PRIVATE.name())) {
+ if (StringUtil.isNotEmpty(ipLocationPrivateReaderV6)) {
+ return ipLocationPrivateReaderV6;
+ } else {
+ return ipLocationPrivateReader;
+ }
+ } else {
+ if (StringUtil.isNotEmpty(ipLocationPublicReaderV6)) {
+ return ipLocationPublicReaderV6;
+ } else {
+ return ipLocationPublicReader;
+ }
+ }
+
+ }
+
+
+
+
+
+
+
+ interface Strategy {
+ LocationResponse getResponse(String ip);
+ }
+
+ /**
+ * 用户自定义IP库的执行策略
+ */
+ class PrivateReader implements Strategy {
+ @Override
+ public LocationResponse getResponse(String ip) {
+ GalaxyDataBaseReader dataBaseReader = null;
+ try {
+ InetAddress ipAddress = InetAddress.getByName(ip);
+
+ if (IPUtil.isIP(ip)) {
+ dataBaseReader = getIpDataBaseReaderV4(ServiceEnum.PRIVATE.name());
+ } else if (IPUtil.isIPv6Address(ip)) {
+ dataBaseReader = getIpDataBaseReaderV6(ServiceEnum.PRIVATE.name());
+ }
+
+ if (StringUtil.isNotEmpty(dataBaseReader)) {
+ return dataBaseReader.location(ipAddress);
+ }
+
+ } catch(AddressNotFoundException addressNotFoundException) {
+ logger.debug("Address not found ,ip is :" + ip);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("ip address :" + ip +", parser error " + e);
+ }
+ return null;
+ }
+ }
+ /**
+ * 第三方服务库的执行策略,例如maxmind、IPDAT
+ */
+ class PublicReader implements Strategy {
+ @Override
+ public LocationResponse getResponse(String ip) {
+ GalaxyDataBaseReader dataBaseReader = null;
+ try {
+ InetAddress ipAddress = InetAddress.getByName(ip);
+
+ if (IPUtil.isIP(ip)) {
+ dataBaseReader = getIpDataBaseReaderV4(ServiceEnum.PUBLIC.name());
+
+ } else if (IPUtil.isIPv6Address(ip)) {
+ dataBaseReader = getIpDataBaseReaderV6(ServiceEnum.PUBLIC.name());
+
+ }
+
+ if (StringUtil.isNotEmpty(dataBaseReader)) {
+ return dataBaseReader.location(ipAddress);
+ }
+
+ } catch(AddressNotFoundException addressNotFoundException) {
+ logger.debug("Address not found ,ip is :" + ip);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("ip address :" + ip +", parser error " + e);
+ }
+ return null;
+
+
+ }
+ }
+
+ /**
+ * 工具类自定义规则库的执行策略
+ */
+ class InnerReader implements Strategy {
+ @Override
+ public LocationResponse getResponse(String ip) {
+ LocationResponse response = null;
+ if (IPUtil.isIP(ip) && IPUtil.internalIp(ip)) {
+ response = new LocationResponse();
+ response.setCountry("Private IP");
+ response.setCity(null);
+ response.setProvince(null);
+ response.setAsn(null);
+ response.setIsp(null);
+ response.setLatitude(null);
+ response.setLongitude(null);
+ response.setAreaCode(null);
+ return response;
+ } else {
+ return null;
+ }
+
+ }
+ }
+
+
+ class Context {
+ private Strategy strategy;
+
+ public Context(Strategy strategy) {
+ this.strategy = strategy;
+ }
+
+ public LocationResponse executeStragey(String ip) {
+ return strategy.getResponse(ip);
+ }
+
+ }
+
+
+
+
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/JsonMapper.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/JsonMapper.java
new file mode 100644
index 0000000..28a9da2
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/JsonMapper.java
@@ -0,0 +1,248 @@
+package com.mesalab.tool.utils;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+
+
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonParser.Feature;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.util.JSONPObject;
+
+/**
+ * 简单封装Jackson,实现JSON String to Java Object的Mapper.
+ * 封装不同的输出风格, 使用不同的builder函数创建实例.
+ * @author darnell
+ */
+public class JsonMapper extends ObjectMapper {
+
+ private static final long serialVersionUID = 1L;
+
+ private static Logger logger = LoggerFactory.getLogger(JsonMapper.class);
+
+ private static JsonMapper mapper;
+
+ public JsonMapper() {
+ this(Include.NON_EMPTY);
+ }
+
+ public JsonMapper(Include include) {
+ // 设置输出时包含属性的风格
+ if (include != null) {
+ this.setSerializationInclusion(include);
+ }
+ // 允许单引号、允许不带引号的字段名称
+ this.enableSimple();
+ // 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
+ this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+ // 空值处理为空串
+ this.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>(){
+ @Override
+ public void serialize(Object value, JsonGenerator jgen,
+ SerializerProvider provider) throws IOException,
+ JsonProcessingException {
+ jgen.writeString("");
+ }
+ });
+ // 进行HTML解码。
+ this.registerModule(new SimpleModule().addSerializer(String.class, new JsonSerializer<String>(){
+ @Override
+ public void serialize(String value, JsonGenerator jgen,
+ SerializerProvider provider) throws IOException,
+ JsonProcessingException {
+ jgen.writeString(StringEscapeUtils.unescapeHtml4(value));
+ }
+ }));
+ // 设置时区
+ this.setTimeZone(TimeZone.getDefault());//getTimeZone("GMT+8:00")
+
+ this.registerModule(new SimpleModule().addSerializer(Date.class, new JsonSerializer<Date>(){
+ @Override
+ public void serialize(Date value, JsonGenerator jgen,
+ SerializerProvider provider) throws IOException,
+ JsonProcessingException {
+
+ SimpleDateFormat sdf = new SimpleDateFormat("EEE, MMM yyyy HH:mm:ss", Locale.US);
+ jgen.writeString(sdf.format(value));
+ }
+ }));
+
+ }
+
+ /**
+ * 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper,建议在外部接口中使用.
+ * @return JsonMapper 生成实例
+ */
+ public static JsonMapper getInstance() {
+ if (mapper == null){
+ mapper = new JsonMapper().enableSimple();
+ }
+ return mapper;
+ }
+
+ /**
+ * 创建只输出初始值被改变的属性到Json字符串的Mapper, 最节约的存储方式,建议在内部接口中使用。
+ * @return JsonMapper 生成实例
+ */
+ public static JsonMapper nonDefaultMapper() {
+ if (mapper == null){
+ mapper = new JsonMapper(Include.NON_DEFAULT);
+ }
+ return mapper;
+ }
+
+ /**
+ * Object可以是POJO,也可以是Collection或数组。
+ * 如果对象为Null, 返回"null".
+ * 如果集合为空集合, 返回"[]".
+ * @return String json字符格式
+ */
+ public String toJson(Object object) {
+ try {
+ return this.writeValueAsString(object);
+ } catch (IOException e) {
+ logger.warn("write to json string error:" + object, e);
+ return null;
+ }
+ }
+
+ /**
+ * 反序列化POJO或简单Collection如List<java.lang.String>.
+ * 如果JSON字符串为Null或"null"字符串, 返回Null.
+ * 如果JSON字符串为"[]", 返回空集合.
+ *
+ * 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String,JavaType)
+ * @see #fromJson(String, JavaType)
+ * @return 反序列化后的对象
+ */
+ public <T> T fromJson(String jsonString, Class<T> clazz) {
+ if (StringUtil.isEmpty(jsonString)) {
+ return null;
+ }
+ try {
+ return this.readValue(jsonString, clazz);
+ } catch (IOException e) {
+ logger.warn("parse json string error:" + jsonString, e);
+ return null;
+ }
+ }
+
+ /**
+ * 反序列化复杂Collection如List<Bean>, 先使用函數createCollectionType构造类型,然后调用本函数.
+ * @see #createCollectionType(Class, Class...)
+ * @return 反序列化后的对象
+ */
+ public <T> T fromJson(String jsonString, JavaType javaType) {
+ if (StringUtil.isEmpty(jsonString)) {
+ return null;
+ }
+ try {
+ return (T) this.readValue(jsonString, javaType);
+ } catch (IOException e) {
+ logger.warn("parse json string error:" + jsonString, e);
+ return null;
+ }
+ }
+
+ /**
+ * 構造泛型的Collection Type如:
+ * ArrayList<MyBean>, 则调用constructCollectionType(ArrayList.class,MyBean.class)
+ * HashMap<String,MyBean>, 则调用(HashMap.class,String.class, MyBean.class)
+ * @return 集合类型
+ */
+ public JavaType createCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
+ return this.getTypeFactory().constructParametricType(collectionClass, elementClasses);
+ }
+
+ /**
+ * 當JSON裡只含有Bean的部分屬性時,更新一個已存在Bean,只覆蓋該部分的屬性.
+ * @return 更新后集合
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T update(String jsonString, T object) {
+ try {
+ return (T) this.readerForUpdating(object).readValue(jsonString);
+ } catch (JsonProcessingException e) {
+ logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e);
+ } catch (IOException e) {
+ logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e);
+ }
+ return null;
+ }
+
+ /**
+ * 輸出JSONP格式數據.
+ */
+ public String toJsonP(String functionName, Object object) {
+ return toJson(new JSONPObject(functionName, object));
+ }
+
+ /**
+ * 設定是否使用Enum的toString函數來讀寫Enum,
+ * 為False時時使用Enum的name()函數來讀寫Enum, 默認為False.
+ * 注意本函數一定要在Mapper創建後, 所有的讀寫動作之前調用.
+ */
+ public JsonMapper enableEnumUseToString() {
+ this.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
+ this.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
+ return this;
+ }
+
+
+
+ /**
+ * 允许单引号
+ * 允许不带引号的字段名称
+ */
+ public JsonMapper enableSimple() {
+ this.configure(Feature.ALLOW_SINGLE_QUOTES, true);
+ this.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
+ return this;
+ }
+
+ /**
+ * 取出Mapper做进一步的设置或使用其他序列化API.
+ */
+ public ObjectMapper getMapper() {
+ return this;
+ }
+
+ /**
+ * 对象转换为JSON字符串
+ * @param object
+ * @return
+ */
+ public static String toJsonString(Object object){
+ return JsonMapper.getInstance().toJson(object);
+ }
+
+ /**
+ * JSON字符串转换为对象
+ * @param jsonString
+ * @param clazz
+ * @return
+ */
+ public static Object fromJsonString(String jsonString, Class<?> clazz){
+ return JsonMapper.getInstance().fromJson(jsonString, clazz);
+ }
+
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/MathUtils.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/MathUtils.java
new file mode 100644
index 0000000..25ebb32
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/MathUtils.java
@@ -0,0 +1,290 @@
+package com.mesalab.tool.utils;
+
+import java.text.DecimalFormat;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+public final class MathUtils {
+
+ private static final String[] byteUnits = new String[]{"B", "KB", "MB", "GB", "TB", "PB"};
+ private static final String[] digitalUnits = new String[]{"", "K", "M"};
+
+ /**
+ *
+ * <p>求和</p>
+ * @param arr 数组对象
+ * @return 求数组和
+ */
+
+ public static double getSum(double[] arr) {
+ double sum = 0;
+ for (double num : arr) {
+ sum += num;
+ }
+ return sum;
+ }
+
+ /**
+ *
+ * <p>求均值</p>
+ * @param arr 数组对象
+ * @return 均值
+ */
+ public static double getMean(double[] arr) {
+ return getSum(arr) / arr.length;
+ }
+
+
+ /**
+ * 求众数
+ * @param arr 数组对象
+ * @return 统计学中的众数,一组数据中出现次数最多的数据
+ */
+ public static double getMode(double[] arr) {
+ Map<Double, Integer> map = new HashMap<Double, Integer>();
+
+ for (int i = 0; i < arr.length; i++) {
+ if (map.containsKey(arr[i])) {
+ map.put(arr[i], map.get(arr[i]) + 1);
+ } else {
+ map.put(arr[i], 1);
+ }
+ }
+ int maxCount = 0;
+ double mode = -1;
+ Iterator<Double> iter = map.keySet().iterator();
+ while (iter.hasNext()) {
+ double num = iter.next();
+ int count = map.get(num);
+ if (count > maxCount) {
+ maxCount = count;
+ mode = num;
+ }
+ }
+ return mode;
+ }
+
+
+ /**
+ * 求中位数
+ * @param arr 数组对象
+ * @return 返回中间数值,偶数个取平均值
+ */
+ public static double getMedian(double[] arr) {
+ double[] tempArr = Arrays.copyOf(arr, arr.length);
+ Arrays.sort(tempArr);
+ if (tempArr.length % 2 == 0) {
+ return (tempArr[tempArr.length >> 1] + tempArr[(tempArr.length >> 1) - 1]) / 2;
+ } else {
+ return tempArr[(tempArr.length >> 1)];
+ }
+ }
+
+
+ /**
+ * 求中列数
+ * @param arr 数组对象
+ * @return 返回中列数,极大值与极小值的平均
+ */
+ public static double getMidRange(double[] arr) {
+ double max = arr[0], min = arr[0];
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i] > max) {
+ max = arr[i];
+ }
+ if (arr[i] < min) {
+ min = arr[i];
+ }
+ }
+ return (min + max) / 2;
+ }
+
+ /**
+ * 求四分位数
+ * @param arr 数组对象
+ * @return 返回四分位数,所有数值由小到大排列并分成四等份,处于三个分割点位置的数值
+ */
+ public static double[] getQuartiles(double[] arr) {
+ double[] tempArr = Arrays.copyOf(arr, arr.length);
+ Arrays.sort(tempArr);
+ double[] quartiles = new double[3];
+ // 第二四分位数(中位数)
+ quartiles[1] = getMedian(tempArr);
+ // 求另外两个四分位数
+ if (tempArr.length % 2 == 0) {
+ quartiles[0] = getMedian(Arrays.copyOfRange(tempArr, 0, tempArr.length / 2));
+ quartiles[2] = getMedian(Arrays.copyOfRange(tempArr, tempArr.length / 2, tempArr.length));
+ } else {
+ quartiles[0] = getMedian(Arrays.copyOfRange(tempArr, 0, tempArr.length / 2));
+ quartiles[2] = getMedian(Arrays.copyOfRange(tempArr, tempArr.length / 2 + 1, tempArr.length));
+ }
+ return quartiles;
+ }
+
+ /**
+ * 求极差
+ * @param arr 数组对象
+ * @return 返回极差,范围误差或全距(Range),最大值与最小值之间的差距,即最大值减最小值后所得之数据
+ */
+ public static double getRange(double[] arr) {
+ double max = arr[0], min = arr[0];
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i] > max) {
+ max = arr[i];
+ }
+ if (arr[i] < min) {
+ min = arr[i];
+ }
+ }
+ return max - min;
+ }
+
+
+
+ /**
+ * 求四分位数极差
+ * @param arr 数组对象
+ * @return 四分位数极差
+ */
+ public static double getQuartilesRange(double[] arr) {
+ return getRange(getQuartiles(arr));
+ }
+
+
+
+ /**
+ * 求截断均值
+ * @param arr 数组对象
+ * @param p 截断量p,例如p的值为20,则截断20%(高10%,低10%)
+ * @return 求截断均值
+ */
+ public static double getTrimmedMean(double[] arr, int p) {
+ int tmp = arr.length * p / 100;
+ double[] tempArr = Arrays.copyOfRange(arr, tmp, arr.length + 1 - tmp);
+ return getMean(tempArr);
+ }
+
+ /**
+ * 求方差
+ * @param arr 数组对象
+ * @return 方差,每个样本值与全体样本值的平均数之差的平方值的平均数
+ */
+ public static double getVariance(double[] arr) {
+ double variance = 0;
+ double sum = 0, sum2 = 0;
+ for (int i = 0; i < arr.length; i++) {
+ sum += arr[i];
+ sum2 += arr[i] * arr[i];
+ }
+ variance = sum2 / arr.length - (sum / arr.length) * (sum / arr.length);
+ return variance;
+ }
+
+ /**
+ * 求绝对平均偏差(AAD)
+ * @param arr 数组对象
+ * @return 绝对平均偏差,实际值和其平均值间差的绝对值的平均,在计算需求的不同差异时使用
+ */
+ public static double getAbsoluteAverageDeviation(double[] arr) {
+ double sum = 0;
+ double mean = getMean(arr);
+ for (int i = 0; i < arr.length; i++) {
+ sum += Math.abs(arr[i] - mean);
+ }
+ return sum / arr.length;
+ }
+
+
+ /**
+ * 求中位数绝对偏差(MAD)
+ * @param arr 数组对象
+ * @return
+ */
+ public static double getMedianAbsoluteDeviation(double[] arr) {
+ double[] tempArr = new double[arr.length];
+ double median = getMedian(arr);
+ for (int i = 0; i < arr.length; i++) {
+ tempArr[i] = Math.abs(arr[i] - median);
+ }
+ return getMedian(tempArr);
+ }
+
+
+ /**
+ * 求标准差
+ * @param arr 数组对象
+ * @return 作为测量一组数值的离散程度之用
+ */
+ public static double getStandardDevition(double[] arr) {
+ double sum = 0;
+ double mean = getMean(arr);
+ for (int i = 0; i < arr.length; i++) {
+ sum += Math.sqrt((arr[i] - mean) * (arr[i] - mean));
+ }
+ return (sum / (arr.length - 1));
+ }
+
+ /**\
+ * 格式化计算机字节为KB 、MB 、TB, 默认保留两位小数
+ * @param byteSize 字节大小单位为B
+ * @return 格式化后内容,byteSize <=0 ,将返回0值
+ */
+ public static String getFormatByteValue(long byteSize) {
+ if (byteSize <= 0) {
+ return "0";
+ }
+ int digitGroups = (int) (Math.log10(byteSize) / Math.log10(1024));
+ if (digitGroups >= byteUnits.length) {
+ digitGroups = byteUnits.length - 1;
+ }
+ return CommonUtil.round( byteSize / Math.pow(1024, digitGroups) ,2 ) + " " + byteUnits[digitGroups];
+ }
+
+
+
+
+ /**\
+ * 格式化数字为K 、M , 默认保留两位小数
+ * @param value 数字
+ * @return 格式化后内容,value <=0 ,将返回0值
+ */
+ public static String getFormatDigitalValue(long value) {
+ if (value <= 0) {
+ return "0";
+ }
+ int digitGroups = (int) (Math.log10(value) / Math.log10(1000));
+ if (digitGroups >= digitalUnits.length) {
+ digitGroups = digitalUnits.length - 1;
+ }
+ return new DecimalFormat("#,##0.##").format( value / Math.pow(1000, digitGroups)) + " " + digitalUnits[digitGroups];
+ }
+
+
+
+ // 138 541 643 988
+ public static void main(String[] args){
+
+ System.out.println(getFormatDigitalValue(100));
+
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/SnowflakeId.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/SnowflakeId.java
new file mode 100644
index 0000000..c326346
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/SnowflakeId.java
@@ -0,0 +1,234 @@
+package com.mesalab.tool.utils;
+
+import org.apache.log4j.Logger;
+
+
+public class SnowflakeId {
+ private static Logger logger = Logger.getLogger(SnowflakeId.class);
+
+ /**
+ * 共64位 第一位为符号位 默认0
+ * 时间戳 39位(17 year), centerId:(关联每个环境或任务数) :7位(0-127),
+ * workerId(关联进程):6(0-63) ,序列号:11位(2047/ms)
+ *
+ * 序列号 /ms = (-1L ^ (-1L << 11))
+ * 最大使用年 = (1L << 39) / (1000L * 60 * 60 * 24 * 365)
+ */
+ /**
+ * 开始时间截 (2020-02-28 00:00:00) max 17years
+ */
+ private final long twepoch = 1582819200000L;
+
+ /**
+ * 机器id所占的位数
+ */
+ private final long workerIdBits = 6L;
+
+ /**
+ * 数据标识id所占的位数
+ */
+ private final long dataCenterIdBits = 7L;
+
+ /**
+ * 支持的最大机器id,结果是63 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
+ * M << n = M * 2^n
+ */
+ private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
+
+ /**
+ * 支持的最大数据标识id,结果是127
+ */
+ private final long maxDataCenterId = -1L ^ (-1L << dataCenterIdBits);
+
+ /**
+ * 序列在id中占的位数
+ */
+ private final long sequenceBits = 11L;
+
+ /**
+ * 机器ID向左移12位
+ */
+ private final long workerIdShift = sequenceBits;
+
+ /**
+ * 数据标识id向左移17位(14+6)
+ */
+ private final long dataCenterIdShift = sequenceBits + workerIdBits;
+
+ /**
+ * 时间截向左移22位(4+6+14)
+ */
+ private final long timestampLeftShift = sequenceBits + workerIdBits + dataCenterIdBits;
+
+ /**
+ * 生成序列的掩码,这里为2047
+ */
+ private final long sequenceMask = -1L ^ (-1L << sequenceBits);
+
+ /**
+ * 工作机器ID(0~63)
+ */
+ private long workerId;
+
+ /**
+ * 数据中心ID(0~127)
+ */
+ private long dataCenterId;
+
+ /**
+ * 毫秒内序列(0~2047)
+ */
+ private long sequence = 0L;
+
+ /**
+ * 上次生成ID的时间截
+ */
+ private long lastTimestamp = -1L;
+
+
+ private static SnowflakeId idWorker;
+
+ private static ZookeeperUtils zookeeperUtils = new ZookeeperUtils();
+ /**
+ * 设置允许时间回拨的最大限制10s
+ */
+ private static final long rollBackTime = 10000L;
+
+ /**
+ * @param workerId
+ * @param dataCenterId
+ */
+ private static void getSnowflakeldInstance(long workerId, long dataCenterId) {
+ idWorker = new SnowflakeId(workerId, dataCenterId);
+ }
+ /**
+ * 依赖于zookeeper
+ * @param zookeeperIp
+ * @param kafkaTopic
+ * @param dataCenterId
+ */
+ private static void getSnowflakeldInstance(String zookeeperIp, long dataCenterId) {
+ idWorker = new SnowflakeId(zookeeperIp, dataCenterId);
+ }
+
+ /**
+ * 构造函数
+ */
+ private SnowflakeId(long tmpWorkerId, long dataCenterIdNum) {
+ if (tmpWorkerId > maxWorkerId || tmpWorkerId < 0) {
+ throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
+ }
+ if (dataCenterIdNum > maxDataCenterId || dataCenterIdNum < 0) {
+ throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than ", maxDataCenterId));
+ }
+ this.workerId = tmpWorkerId;
+ this.dataCenterId = dataCenterIdNum;
+
+ }
+
+ private SnowflakeId(String zookeeperIp, long dataCenterIdNum) {
+ ZooKeeperLock lock = new ZooKeeperLock(zookeeperIp, "/locks", "disLocks1");
+ if (lock.lock()) {
+ int tmpWorkerId = zookeeperUtils.modifyNode("/Snowflake/" + "worker" + dataCenterIdNum, zookeeperIp);
+ if (tmpWorkerId > maxWorkerId || tmpWorkerId < 0) {
+ throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
+ }
+ if (dataCenterIdNum > maxDataCenterId || dataCenterIdNum < 0) {
+ throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than ", maxDataCenterId));
+ }
+ this.workerId = tmpWorkerId;
+ this.dataCenterId = dataCenterIdNum;
+ try {
+ lock.unlock();
+ } catch (InterruptedException ie) {
+ ie.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ logger.error("This is not usual error!!!===>>>" + e + "<<<===");
+ }
+ }
+ }
+ /**
+ * 获得下一个ID (该方法是线程安全的)
+ *
+ * @return SnowflakeId
+ */
+ private synchronized long nextId() {
+ long timestamp = timeGen();
+ //设置一个允许回拨限制时间,系统时间回拨范围在rollBackTime内可以等待校准
+ if (lastTimestamp - timestamp > 0 && lastTimestamp - timestamp < rollBackTime) {
+ timestamp = tilNextMillis(lastTimestamp);
+ }
+ //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
+ if (timestamp < lastTimestamp) {
+ throw new RuntimeException(
+ String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
+ }
+
+ //如果是同一时间生成的,则进行毫秒内序列
+ if (lastTimestamp == timestamp) {
+ sequence = (sequence + 1) & sequenceMask;
+ //毫秒内序列溢出
+ if (sequence == 0) {
+ //阻塞到下一个毫秒,获得新的时间戳
+ timestamp = tilNextMillis(lastTimestamp);
+ }
+ }
+ //时间戳改变,毫秒内序列重置
+ else {
+ sequence = 0L;
+ }
+
+ //上次生成ID的时间截
+ lastTimestamp = timestamp;
+
+ //移位并通过或运算拼到一起组成64位的ID
+ return ((timestamp - twepoch) << timestampLeftShift)
+ | (dataCenterId << dataCenterIdShift)
+ | (workerId << workerIdShift)
+ | sequence;
+ }
+
+ /**
+ * 阻塞到下一个毫秒,直到获得新的时间戳
+ *
+ * @param lastTimestamp 上次生成ID的时间截
+ * @return 当前时间戳
+ */
+ protected long tilNextMillis(long lastTimestamp) {
+ long timestamp = timeGen();
+ while (timestamp <= lastTimestamp) {
+ timestamp = timeGen();
+ }
+ return timestamp;
+ }
+
+ /**
+ * 返回以毫秒为单位的当前时间
+ *
+ * @return 当前时间(毫秒)
+ */
+ protected long timeGen() {
+ return System.currentTimeMillis();
+ }
+
+ public static Long generateId(long workerId, long dataCenterIdNum) {
+ if (idWorker == null) {
+ getSnowflakeldInstance(workerId, dataCenterIdNum);
+ }
+ return idWorker.nextId();
+ }
+
+ /**
+ * 静态工具类
+ *
+ * @return
+ */
+ public synchronized static Long generateId(String zookeeperIp, long dataCenterIdNum) {
+ if (idWorker == null) {
+ getSnowflakeldInstance(zookeeperIp, dataCenterIdNum);
+ }
+ return idWorker.nextId();
+ }
+
+} \ No newline at end of file
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/StringUtil.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/StringUtil.java
new file mode 100644
index 0000000..05b15e4
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/StringUtil.java
@@ -0,0 +1,729 @@
+package com.mesalab.tool.utils;
+
+
+import org.apache.commons.lang3.StringUtils;
+import sun.misc.BASE64Encoder;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
+ * <p>字符串处理工具类</p>
+ * @author 中电积至有限公司
+ * @version 1.0 创建时间:2010-11-8 下午04:50:39
+ *
+ */
+
+
+public final class StringUtil extends StringUtils {
+
+ private static int size = 0;
+
+ private static final String[] SIMPLIFIED_CASE = { "O", "一", "二", "三", "四", "五",
+ "六", "七", "八", "九", "十" };
+
+ private static final String[] TRADITIONAL_CASE = { "零", "壹", "贰", "叁", "肆", "伍",
+ "陆", "柒", "捌", "玖", "拾" };
+
+ private static final String PATTERN_EMPTY_FULL = "[\u4e00-\u9fa5]";
+ private static final String PATTERN_EMPTY_CHARACTER = "\\s*|\t|\r|\n";
+
+ /**
+ * The empty String <code>""</code>.
+ */
+ public static final String EMPTY = "";
+
+ /**
+ *空 <code>String</code> 数组.
+ */
+ public static final String[] EMPTY_STRING_ARRAY = new String[0];
+ public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+
+ /**
+ * ISO8859_1 编码集
+ */
+ public static final String CODE_ISO8859_1 = "ISO8859_1";
+ /**
+ * GB2312 编码集
+ */
+ public static final String CODE_GB2312 = "GB2312";
+ /**
+ * GBK 编码集
+ */
+ public static final String CODE_GBK = "GBK";
+ /**
+ * UTF-8 编码集
+ */
+ public static final String CODE_UTF_8 = "UTF-8";
+
+
+ /**
+ *<p>Description:抑制默认的构造器,避免实例化对象 </p>
+ */
+ private StringUtil() {
+
+ }
+
+ /**
+ *
+ * <p>判断一个对象是否为空</p>
+ * <p>
+ * <code>object</code>元素判断所有对象是否为空.
+ * 另外对{@link String}、{@link Collection}及其子类 、{@link Map}及其子类、数组 进行长度验证,如果长度为0,视为空对象.
+ * </p>
+ * <pre>
+ * String aa = " ";
+ * List list = new ArrayList()
+ * LinkedHashSet set = new LinkedHashSet();
+ * StringUtil.isEmpty(aa) = true
+ * StringUtil.isEmpty(list) = true
+ * StringUtil.isEmpty(set) = true
+ * StringUtil.isEmpty("\t") = true
+ * </pre>
+ * @param object 对象元素
+ * @return <code>true</code> 对象为<code>null</code>,<code>false</code> 对象不为<code>null</code>.
+ */
+ public static boolean isEmpty(Object object) {
+ initSize(object);
+ return size == 0;
+ }
+
+
+ /**
+ *
+ * <p>判断一个对象不为空</p>
+ * <p>
+ * <code>object</code>元素判断不为空验证
+ * 另外对{@link String}、{@link Collection}及其子类 、{@link Map}及其子类、数组 进行长度验证,如果长度为0,视为空对象.
+ * </p>
+ * <pre>
+ * String aa = " ";
+ * List list = new ArrayList()
+ * LinkedHashSet set = new LinkedHashSet();
+ * StringUtil.isNotEmpty(aa) = false
+ * StringUtil.isEmpty(list) = false
+ * StringUtil.isEmpty(set) = false
+ * StringUtil.isEmpty("\t") = false
+ * </pre>
+ * @param object 对象元素
+ * @return <code>true</code> 对象为<code>null</code>,<code>false</code> 对象不为<code>null</code>.
+ */
+ public static boolean isNotEmpty(Object object) {
+ initSize(object);
+ return size != 0;
+ }
+
+
+ /**
+ *
+ * 判断对象是否有数据存在? 不存在为0、存在不为0的值.
+ * @param object 对象值
+ */
+ private static void initSize(Object object){
+ if (object == null) {
+ size = 0;
+ } else {
+ if (object instanceof String) {
+ size = isBlank((String)object)?0:1;
+ } else if (object instanceof Collection) {
+ size = ((Collection)object).size();
+ } else if (object instanceof Map) {
+ size = ((Map)object).size();
+ } else if (object instanceof Object[]) {
+ Object[] objectArray = (Object[])object;
+ size = objectArray.length;
+ //其他数据类型
+ } else {
+ size = 1;
+ }
+
+ }
+
+ }
+
+
+
+
+
+ /**
+ * <p>判断字符串是否为空.
+ * 为空条件:全角\半角\tab 等没有实际意义的字符.
+ * 具体参看{@link Character#isWhitespace(char)}对空格的定义.
+ * </p>
+ *
+ * <pre>
+ * StringUtils.isBlank(" ") = true 为半角空格
+ * StringUtils.isBlank("  ") = true 为全角空格
+ * StringUtils.isBlank(" ") = true 为tab键
+ * </pre>
+ * @param str 字符串
+ * @return <code>true</code> 字符串为空 ,<code>false</code> 不为空
+ */
+ public static boolean isBlank(String str) {
+ int strLen;
+ if (str == null || (strLen = str.length()) == 0) {
+ return true;
+ }
+ for (int i = 0; i < strLen; i++) {
+ if (!Character.isWhitespace(str.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ *
+ * <p>判断字符串不为空.
+ * 为空条件:全角\半角\tab 等没有实际意义的字符.
+ * 具体参看{@link Character#isWhitespace(char)}对空格的定义.
+ * </p>
+ * <pre>
+ * StringUtils.isBlank(" ") = false 为半角空格
+ * StringUtils.isBlank("  ") = false 为全角空格
+ * StringUtils.isBlank(" ") = false 为tab键
+ * </pre>
+ * @param str 字符串
+ * @return <code>true</code> 字符串为空 ,<code>false</code> 不为空
+ */
+ public static boolean isNotBlank(String str) {
+ return !isBlank(str);
+ }
+
+
+
+ /**
+ *
+ * <p>
+ * 获得文件扩展名
+ * TXT,HTML,HTM,EML,DOC,DOCX,XLS,XLSX,PPT,PPTX,PDF
+ * </p>
+ * @param filePath 文件路径
+ * @return <code>string</code> 扩展名 ,<code>null</code> 无扩展名
+ */
+ public static String getFileExtendName(String filePath){
+ String extendName = null;
+ if(filePath.lastIndexOf(".")!=-1){
+ extendName = filePath.substring(filePath.lastIndexOf(".")+1).trim().toUpperCase();
+ }
+ return extendName;
+ }
+
+
+
+
+ /**
+ *
+ * <p>去掉字符串两边空格.
+ * 去掉空格规则:
+ * 半角\全角\tab等无实际意义的字符.
+ * 具体参看{@link Character#isWhitespace(char)}对空格的定义.
+ * </p>
+ * <pre>
+ * StringUtil.strip("  aa  ").length() = 2
+ * StringUtil.strip(" ").length() = 0
+ * </pre>
+ * @param str 字符
+ * @return <code>str</code> 两边去空后字符串,<code>""</code> 字符串为null时.
+ */
+ public static String strip(String str){
+
+ if(isEmpty(str)){
+ return EMPTY;
+ }
+ int start = 0;
+ int end = str.length();
+ //去掉前边空格
+ while ((start != end) && Character.isWhitespace(str.charAt(start))) {
+ start++;
+ }
+ //去掉后边空格
+ while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) {
+ end--;
+ }
+
+ return str.substring(start,end);
+ }
+
+ /**
+ *
+ * <p>去掉字符串空格,如果为中文去掉所有空格,英文去两边空格。
+ * 去掉空格规则:
+ * 半角\全角\tab等无实际意义的字符.
+ *
+ * </p>
+ * <pre>
+ * StringUtil.strip("  a a  ").length() = 2
+ * StringUtil.strip(" ").length() = 0
+ * </pre>
+ * @param str 字符
+ * @return <code>str</code> 去空后字符串,<code>""<code> 字符串为null时.
+ */
+ public static String stripAll(String str){
+ String dest="";
+ Pattern p = Pattern.compile(PATTERN_EMPTY_FULL);
+ Matcher m = p.matcher(str);
+ if(m.find()){
+ if(str != null){
+ p = Pattern.compile(PATTERN_EMPTY_CHARACTER);
+ str = str.replace((char)12288,' ');
+ Matcher matcher = p.matcher(str);
+ dest = matcher.replaceAll("");
+ }
+ }else {
+ dest = str.trim();
+ }
+
+ return dest;
+ }
+
+
+ /**
+ *
+ * <p>如果对象为空时,返回默认值.</p>
+ * @param object 要判断是否为空的对象
+ * @param defaultValue 为空时设的默认值
+ * @see #isEmpty(Object)
+ * @return 获取处理后的数据
+ */
+ public static Object setDefaultIfEmpty(Object object,Object defaultValue){
+
+ return isEmpty(object)?defaultValue:object;
+ }
+
+ /**
+ *
+ * <p>对字符串进行MD5加密.</p>
+ * <p>
+ * 一般作为密码的处理方式,首先通过MD5进行加密,然后将字符串进行Base64编码获得所需字符.
+ * </p>
+ * <pre>
+ * String str = "ceshi";
+ * StringUtil.md5(str) = "zBfDDNERxyFfyPUfh5Dg4Q=="
+ * </pre>
+ * @param msg 要加密的字符串
+ * @return 返回加密后的25位字符,如果解析出现异常将返回<code>null</code>.
+ */
+ public static String md5(String msg) {
+ try {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] b = md.digest(msg.getBytes());
+ BASE64Encoder encoder = new BASE64Encoder();
+ return encoder.encode(b);
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ return EMPTY;
+ }
+ }
+
+
+ /**
+ * <p>截取处理字符串,当字符串超过指定的截取长度时,用“......”补充</p>
+ * <pre>
+ * String str = "中华人民共和国";
+ * StringUtil.getMoreString(str, 6) = "中华人民共和......"
+ * </pre>
+ * @param text 字符串数据
+ * @param length 截取的长度值
+ * @return 返回处理后字符
+ */
+ public static String getMoreString(String text,int length){
+ StringBuilder textBuilder = new StringBuilder();
+
+ if(isEmpty(text)){
+ return EMPTY;
+ }
+ int endIndex = Math.min(length, text.length());
+ if(endIndex==length){
+ text = text.substring(0,length);
+ textBuilder.append(text).append("......");
+ }else {
+ textBuilder.append(text);
+ }
+
+
+ return textBuilder.toString();
+ }
+
+
+
+
+ /**
+ *
+ * <p>按照规则解析字符串得到一个数组.</p>
+ * <pre>
+ * StringUtil.Split(null, "*") = null
+ * StringUtil.Split("", *) = []
+ * StringUtil.Split("a.b.c", ".") = ["a", "b", "c"]
+ * StringUtil.Split("a\tb\nc", null) = []
+ * StringUtil.Split("a b c", " ") = ["a", "b", "c"]
+ * </pre>
+ * @param str 需要分隔的字符串
+ * @param regex 分隔规则
+ * @return 返回字符串数组,如果分隔字符串为空返回<code>null</code>.
+ */
+ public static String[] split(String str,String regex) {
+
+ if(str == null){
+ return null;
+ }
+
+ if(str.length() == 0 || regex == null){
+ return EMPTY_STRING_ARRAY;
+ }
+
+
+ return str.split(regex);
+
+ }
+
+ /**
+ *
+ * <p>判断字符集编码是否在java中支持.</p>
+ * @param name 所要求的字符集
+ * @return <code>true</code> java 虚拟机下支持该字符集,<code>false</code> 不支持该字符集
+ */
+ public static boolean isSupported(String name) {
+ if (name == null) {
+ return false;
+ }
+ try {
+ new String(EMPTY_BYTE_ARRAY, name);
+ } catch (UnsupportedEncodingException e) {
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ *
+ * <p>字符编码转换,需要提供字符串的源编码与目的编码格式.</p>
+ * <p>
+ * 字符串工具类中提供一些字符编码常量:
+ * {@link #CODE_GB2312}\{@link #CODE_GBK}\{@link #CODE_ISO8859_1}\{@link #CODE_UTF_8}
+ * </p>
+ * @param value 要编码的值
+ * @param sourceCodingFormat 字符的原始编码格式,具体编码格式可看本类提供的编码样式.
+ * @param destCodingFormat 要转换字符的编码格式,具体编码格式可看本类提供的编码样式.
+ * @return 返回编码后的字符串.
+ * @throws UnsupportedEncodingException
+ */
+ public static String getCodingConversionResult(String value,String sourceCodingFormat,
+ String destCodingFormat ) throws UnsupportedEncodingException{
+
+ if(!isSupported(sourceCodingFormat) || !isSupported(destCodingFormat)){
+ throw new UnsupportedEncodingException("JVM 下不支持该字符集编码");
+ }
+
+ if(isEmpty(value)){
+ return EMPTY;
+ }
+
+
+ return new String(value.getBytes(sourceCodingFormat), destCodingFormat);
+ }
+
+
+
+
+ /**
+ *
+ * <p>判断字符串是否是数字格式(包括小数形式).</p>
+ * <pre>
+ * String a1 = "12";
+ * String a2 = "0.01";
+ * String a3 = "0.0.1";
+ * String a4 = "123a";
+ * StringUtil.isNumeric(a1) = true
+ * StringUtil.isNumeric(a2) = true
+ * StringUtil.isNumeric(a3) = false
+ * StringUtil.isNumeric(a4) = false
+ * </pre>
+ * @param numberString 数字格式字符串
+ * @return <code>true</code> 符合数字格式(包括小数),<code>false</code> 不符合数字格式.
+ */
+ public static boolean isNumeric(String numberString){
+
+ if(isEmpty(numberString)){
+ return false;
+ }
+
+ if(numberString.startsWith(".")||numberString.endsWith(".")){
+ return false;
+ }
+
+ int length = numberString.split("\\.").length-1; //判断小数点在字符串中出现的次数。
+
+
+ if(length>1) { //小数点大于1次,不符合数字规范
+
+ return false;
+ }
+
+
+ for(int i=0; i<numberString.length(); i++){
+ if(!Character.isDigit(numberString.charAt(i))&&!".".equals(String.valueOf(numberString.charAt(i)))){
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ *
+ * <p>压缩字符串</p>
+ * <p>
+ * 将带有换行\回车等字符替换为空格格式.具体替换有:
+ * \t,\n,\f,\r .
+ * </p>
+ * <pre>
+ * StringUtil.compressString("ceshi\too\f") = "ceshi oo "
+ * </pre>
+ * @param text 要替换的字符串,可能为<code>null</code>
+ */
+ public static String compressString(String text){
+ if(isBlank(text)){
+ return text;
+ }
+ return text.replaceAll("[ \t\n\f\r ]+"," ");
+ }
+
+ /**
+ *
+ * <p>将查找的字符串全部替换为设置的字符串</p>
+ * <p>
+ * 当该方法无操作时,返回<code>null</code>引用.
+ * </p>
+ * <pre>
+ * StringUtil.replace(null, "*","*") = null
+ * StringUtil.replace("str", null, "*") = "str"
+ * StringUtil.replace("ceshi", "c", "") = "eshi"
+ * StringUtil.replace("aba", "a", "z") = "zbz"
+ * </pre>
+ * @see #replace(String, String, String, int)
+ * @param text 需处理的字符串
+ * @param searchString 查找的字符
+ * @param replaceString 替换的字符
+ * @return 返回替换后的字符串,文本为空时返回null.
+ */
+ public static String replace(String text, String searchString, String replaceString ){
+
+ return replace(text, searchString, replaceString, -1);
+ }
+
+ /**
+ *
+ * <p>将查找字符串替换为设置字符串,根据<code>count</code>决定替换几次.
+ * 当<code>text</code> 为空不进行任何操作..
+ * </p>
+ * <pre>
+ * StringUtil.replace("abaa", "a", null, -1) = "abaa"
+ * StringUtil.replace("abaa", "a", "", -1) = "b"
+ * StringUtil.replace("abaa", "a", "z", 0) = "abaa"
+ * StringUtil.replace("abaa", "a", "z", 1) = "zbaa"
+ * </pre>
+ * @param text 需要处理的字符串
+ * @param searchString 查找的字符
+ * @param replaceString 替换字符
+ * @param count 替换的总次数,<code>-1</code> 替换所有满足条件的字符,<code>0</code> 不进行替换.
+ * @return 返回替换后的字符串,文本为空时返回null.
+ */
+ public static String replace(String text, String searchString, String replaceString, int count) {
+
+ if (isBlank(text) || isBlank(searchString) || replaceString == null || count == 0) {
+ return text;
+ }
+
+ int start = 0;
+ int end = text.indexOf(searchString, start);
+ if (end == -1) {
+ return text;
+ }
+ int replLength = searchString.length();
+
+ int increase = replaceString.length() - replLength;
+ increase = (increase < 0 ? 0 : increase);
+ increase *= (count < 0 ? 16 : (count > 64 ? 64 : count));
+ StringBuffer buf = new StringBuffer(text.length() + increase);
+ while (end != -1) {
+ buf.append(text.substring(start, end)).append(replaceString);
+ start = end + replLength;
+ if (--count == 0) {
+ break;
+ }
+ end = text.indexOf(searchString, start);
+ }
+ buf.append(text.substring(start));
+ return buf.toString();
+
+ }
+
+
+
+ /**
+ *
+ * <p>将字符串数字转换为简体大写中文格式.</p>
+ * <pre>
+ * StringUtil.convertSimplifiedCase("325") = ”三二五"
+ * </pre>
+ * @param numberString 数字字符串
+ * @return 返回简体大写后的数字
+ */
+ public static String convertSimplifiedCase(String numberString) {
+
+ StringBuilder simplifiedBuilder = new StringBuilder();
+
+ if(isEmpty(numberString)){
+ return null;
+ }
+
+
+ for (int i = 0; i < numberString.length(); i++) {
+ String tempNumberString = String.valueOf(numberString.charAt(i));
+ if ("0123456789".indexOf(tempNumberString) >= 0) {
+ int number = Integer.parseInt(tempNumberString);
+ simplifiedBuilder.append(SIMPLIFIED_CASE[number]);
+ } else {
+ simplifiedBuilder.append(tempNumberString);
+ }
+ }
+
+ return simplifiedBuilder.toString();
+ }
+
+
+ /**
+ *
+ * <p>把字符串中的数字转换成繁体大写中文的格式.</p>
+ * <pre>
+ * StringUtil.convertTraditionalCase("325") = "叁贰伍"
+ * </pre>
+ * @param numberString 数字字符串
+ * @return 返回繁体大写后的数字
+ */
+ public static String convertTraditionalCase(String numberString) {
+
+ StringBuilder simplifiedBuilder = new StringBuilder();
+
+ if(isEmpty(numberString)){
+ return null;
+ }
+
+
+ for (int i = 0; i < numberString.length(); i++) {
+ String tempNumberString = String.valueOf(numberString.charAt(i));
+ if ("0123456789".indexOf(tempNumberString) >= 0) {
+ int number = Integer.parseInt(tempNumberString);
+ simplifiedBuilder.append(TRADITIONAL_CASE[number]);
+ } else {
+ simplifiedBuilder.append(tempNumberString);
+ }
+ }
+
+ return simplifiedBuilder.toString();
+ }
+
+ /**
+ *
+ * <p>创建唯一标识字符串.</p>
+ * <pre>
+ * StringUtil.createUUID() = "00000DAF3CFC4E0B8DF2D5BEACB14D75"
+ * </pre>
+ * @return 返回标识符字符串
+ */
+ public static String createUUID() {
+ String uuid = UUID.randomUUID().toString();
+ uuid = uuid.replace("-", "");
+ return uuid.toUpperCase();
+ }
+
+
+ /**
+ *
+ * <p>字符串过滤,负责将html的textarea属性获得的字符转换成html格式的字符集.</p>
+ * @param str 要解析的字符串
+ * @return 是解析后的字符串
+ */
+ public static String htmlFilter(String str) {
+ StringBuffer stringbuffer = new StringBuffer();
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ switch (c) {
+
+ case 39:
+ stringbuffer.append("&#039;");
+ break;
+
+ case 34:
+ stringbuffer.append("&quot;");
+ break;
+
+ case 60:
+ stringbuffer.append("&lt;");
+ break;
+
+ case 62:
+ stringbuffer.append("&gt;");
+ break;
+
+ case 38:
+ stringbuffer.append("&amp;");
+ break;
+
+ case 32:
+ stringbuffer.append("&#32;");
+ break;
+
+ case 10:
+ stringbuffer.append("<br>");
+ break;
+
+ case 8220:
+ stringbuffer.append("&ldquo;");
+ break;
+
+ case 8221:
+ stringbuffer.append("&rdquo;");
+ break;
+
+ default:
+ stringbuffer.append(c);
+ break;
+ }
+ }
+
+ return stringbuffer.toString();
+ }
+
+
+ /**
+ *
+ * @Title: getFromRegEx
+ * @Description: 统一正则抽取字符方法
+ * @param str
+ * @param pattern
+ * @param index
+ * @return String 返回类型
+ * @author (darnell) 2017年8月21日 下午4:25:31
+ */
+ public static String getFromRegEx(String str, String pattern, int index) {
+ String value = "";
+ Pattern p = Pattern.compile(pattern);
+ Matcher matcher = p.matcher(str);
+ while(matcher.find()) {
+ value = matcher.group(index);
+ }
+ return value;
+ }
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/TimeConstants.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/TimeConstants.java
new file mode 100644
index 0000000..6dacc6a
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/TimeConstants.java
@@ -0,0 +1,40 @@
+package com.mesalab.tool.utils;
+
+/**
+ *
+ * <p>日期常量</p>
+ * @author 中电积至有限公司 darnell
+ * @version 1.0 创建时间:2011-07-07 下午11:24:57
+ *
+ */
+public interface TimeConstants {
+ /**
+ * 处理日期时,用到参数。格式24小时制yyyy-MM-dd HH:mm:ss
+ */
+ String YYYY_MM_DD_HH24_MM_SS = "yyyy-MM-dd HH:mm:ss";
+ /**
+ * 处理日期时,用到参数。格式12小时制yyyy-MM-dd hh:mm:ss
+ */
+ String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd hh:mm:ss";
+ /**
+ * 处理日期时,用到参数。格式为yyyy-MM-dd
+ */
+ String YYYY_MM_DD = "yyyy-MM-dd";
+ /**
+ * 处理日期时,用到参数。格式24小时制yyyy-MM-dd HH:mm
+ */
+ String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
+ /**
+ * 处理日期时,用到参数。格式24小时制yyyyMMddHHmmss
+ */
+ String YYYYMMDDHH24MMSS = "yyyyMMddHHmmss";
+ /**
+ * 处理日期时,用到参数。格式为yyyyMMdd
+ */
+ String YYYYMMDD = "yyyyMMdd";
+ /**
+ * 处理日期时,用到参数。格式为HHmmss
+ */
+ String HH24MMSS = "HHmmss";
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/ZooKeeperLock.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/ZooKeeperLock.java
new file mode 100644
index 0000000..bb41a52
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/ZooKeeperLock.java
@@ -0,0 +1,140 @@
+package com.mesalab.tool.utils;
+
+import org.apache.log4j.Logger;
+import org.apache.zookeeper.*;
+import org.apache.zookeeper.data.Stat;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class ZooKeeperLock implements Watcher {
+ private static Logger logger = Logger.getLogger(ZooKeeperLock.class);
+
+ private ZooKeeper zk = null;
+ private String rootLockNode; // 锁的根节点
+ private String lockName; // 竞争资源,用来生成子节点名称
+ private String currentLock; // 当前锁
+ private String waitLock; // 等待的锁(前一个锁)
+ private CountDownLatch countDownLatch; // 计数器(用来在加锁失败时阻塞加锁线程)
+ private int sessionTimeout = 30000; // 超时时间
+
+ // 1. 构造器中创建ZK链接,创建锁的根节点
+ public ZooKeeperLock(String zkAddress, String rootLockNode, String lockName) {
+ this.rootLockNode = rootLockNode;
+ this.lockName = lockName;
+ try {
+ // 创建连接,zkAddress格式为:IP:PORT
+ zk = new ZooKeeper(zkAddress, this.sessionTimeout, this);
+ // 检测锁的根节点是否存在,不存在则创建
+ Stat stat = zk.exists(rootLockNode, false);
+ if (null == stat) {
+ zk.create(rootLockNode, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+ }
+ } catch (IOException | InterruptedException | KeeperException e) {
+ e.printStackTrace();
+ logger.error("ZooKeeperLock Constructors ===>>>Node already exists!");
+ }
+ }
+
+ // 2. 加锁方法,先尝试加锁,不能加锁则等待上一个锁的释放
+ public boolean lock() {
+ if (this.tryLock()) {
+ logger.warn("ZooKeeperLock method lock() ===>>> zkLockProcess[[[" + Thread.currentThread().getName() + "]]] addZkLock(" + this.currentLock + ")success!");
+ return true;
+ } else {
+ return waitOtherLock(this.waitLock, this.sessionTimeout);
+ }
+ }
+
+ public boolean tryLock() {
+ // 分隔符
+ String split = "_lock_";
+ if (this.lockName.contains("_lock_")) {
+ throw new RuntimeException("lockName can't contains '_lock_' ");
+ }
+ try {
+ // 创建锁节点(临时有序节点)
+ this.currentLock = zk.create(this.rootLockNode + "/" + this.lockName + split, new byte[0],
+ ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
+ logger.warn("ZooKeeperLock method tryLock() ===>>> zkLockProcess[[[" + Thread.currentThread().getName() + "]]] create zkLockNode(" + this.currentLock + ")success,begin to election...");
+ // 取所有子节点
+ List<String> nodes = zk.getChildren(this.rootLockNode, false);
+ // 取所有竞争lockName的锁
+ List<String> lockNodes = new ArrayList<String>();
+ for (String nodeName : nodes) {
+ if (nodeName.split(split)[0].equals(this.lockName)) {
+ lockNodes.add(nodeName);
+ }
+ }
+ Collections.sort(lockNodes);
+ // 取最小节点与当前锁节点比对加锁
+ String currentLockPath = this.rootLockNode + "/" + lockNodes.get(0);
+ if (this.currentLock.equals(currentLockPath)) {
+ return true;
+ }
+ // 加锁失败,设置前一节点为等待锁节点
+ String currentLockNode = this.currentLock.substring(this.currentLock.lastIndexOf("/") + 1);
+ int preNodeIndex = Collections.binarySearch(lockNodes, currentLockNode) - 1;
+ this.waitLock = lockNodes.get(preNodeIndex);
+ } catch (KeeperException | InterruptedException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ private boolean waitOtherLock(String waitLock, int sessionTimeout) {
+ boolean islock = false;
+ try {
+ // 监听等待锁节点
+ String waitLockNode = this.rootLockNode + "/" + waitLock;
+ Stat stat = zk.exists(waitLockNode, true);
+ if (null != stat) {
+ logger.error("ZooKeeperLock method waitOtherLock() ===>>> zkLockProcess[[[" + Thread.currentThread().getName() + "]]] zkLock(" + this.currentLock + ")addZkLock fail,wait lock(" + waitLockNode + ")release...");
+ // 设置计数器,使用计数器阻塞线程
+ this.countDownLatch = new CountDownLatch(1);
+ islock = this.countDownLatch.await(sessionTimeout, TimeUnit.MILLISECONDS);
+ this.countDownLatch = null;
+ if (islock) {
+ logger.warn("ZooKeeperLock method waitOtherLock() ===>>> zkLockProcess[[[" + Thread.currentThread().getName() + "]]] zkLock(" + this.currentLock + ")addZkLock success,lock(" + waitLockNode + ")release over.");
+ } else {
+ logger.error("ZooKeeperLock method waitOtherLock() ===>>> zkLockProcess[[[" + Thread.currentThread().getName() + "]]] zkLock(" + this.currentLock + "addZkLock fail...");
+ }
+ } else {
+ islock = true;
+ }
+ } catch (KeeperException | InterruptedException e) {
+ e.printStackTrace();
+ }
+ return islock;
+ }
+
+ // 3. 释放锁
+ public void unlock() throws InterruptedException {
+ try {
+ Stat stat = zk.exists(this.currentLock, false);
+ if (null != stat) {
+ logger.warn("ZooKeeperLock method unlock() ===>>> zkLockProcess[[[" + Thread.currentThread().getName() + "]]] free zkLock " + this.currentLock);
+ zk.delete(this.currentLock, -1);
+ this.currentLock = null;
+ }
+ } catch (InterruptedException | KeeperException e) {
+ e.printStackTrace();
+ } finally {
+ zk.close();
+ }
+ }
+
+ // 4. 监听器回调
+ @Override
+ public void process(WatchedEvent watchedEvent) {
+ if (null != this.countDownLatch && watchedEvent.getType() == Event.EventType.NodeDeleted) {
+ // 计数器减一,恢复线程操作
+ this.countDownLatch.countDown();
+ }
+ }
+
+}
diff --git a/galaxy-tool/src/main/java/com/mesalab/tool/utils/ZookeeperUtils.java b/galaxy-tool/src/main/java/com/mesalab/tool/utils/ZookeeperUtils.java
new file mode 100644
index 0000000..e4c0a1d
--- /dev/null
+++ b/galaxy-tool/src/main/java/com/mesalab/tool/utils/ZookeeperUtils.java
@@ -0,0 +1,139 @@
+package com.mesalab.tool.utils;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.log4j.Logger;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Stat;
+
+
+public class ZookeeperUtils implements Watcher {
+ private static Logger logger = Logger.getLogger(ZookeeperUtils.class);
+
+ private ZooKeeper zookeeper;
+
+ private static final int SESSION_TIME_OUT = 20000;
+
+ private CountDownLatch countDownLatch = new CountDownLatch(1);
+
+ @Override
+ public void process(WatchedEvent event) {
+ if (event.getState() == Event.KeeperState.SyncConnected) {
+ countDownLatch.countDown();
+ }
+ }
+
+
+ /**
+ * 修改节点信息
+ *
+ * @param path 节点路径
+ */
+ public int modifyNode(String path, String zookeeperIp) {
+ createNode(path, "0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, zookeeperIp);
+ int workerId = 0;
+ try {
+ connectZookeeper(zookeeperIp);
+ Stat stat = zookeeper.exists(path, true);
+ workerId = Integer.parseInt(getNodeDate(path));
+ if (workerId > 63) {
+ workerId = 0;
+ zookeeper.setData(path, "1".getBytes(), stat.getVersion());
+ } else {
+ String result = String.valueOf(workerId + 1);
+ if (stat != null) {
+ zookeeper.setData(path, result.getBytes(), stat.getVersion());
+ } else {
+ logger.error("Node does not exist!,Can't modify");
+ }
+ }
+ } catch (KeeperException | InterruptedException e) {
+ logger.error("modify error Can't modify,"+e.getMessage());
+ }
+ finally {
+ closeConn();
+ }
+ logger.warn("workerID is:" + workerId);
+ return workerId;
+ }
+
+ /**
+ * 连接zookeeper
+ *
+ * @param host 地址
+ */
+ public void connectZookeeper(String host) {
+ try {
+ zookeeper = new ZooKeeper(host, SESSION_TIME_OUT, this);
+ countDownLatch.await();
+ } catch (IOException | InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 关闭连接
+ */
+ public void closeConn() {
+ try {
+ if (zookeeper != null) {
+ zookeeper.close();
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 获取节点内容
+ *
+ * @param path 节点路径
+ * @return 内容/异常null
+ */
+ public String getNodeDate(String path) {
+ String result = null;
+ Stat stat = new Stat();
+ try {
+ byte[] resByte = zookeeper.getData(path, true, stat);
+ result = new String(resByte);
+ } catch (KeeperException | InterruptedException e) {
+ logger.error("Get node information exception");
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ /**
+ * @param path 节点创建的路径
+ * @param date 节点所存储的数据的byte[]
+ * @param acls 控制权限策略
+ */
+ public void createNode(String path, byte[] date, List<ACL> acls, String zookeeperIp) {
+ try {
+ connectZookeeper(zookeeperIp);
+ Stat exists = zookeeper.exists(path, true);
+ if (exists == null) {
+ Stat existsSnowflakeld = zookeeper.exists("/Snowflake", true);
+ if (existsSnowflakeld == null) {
+ zookeeper.create("/Snowflake", null, acls, CreateMode.PERSISTENT);
+ }
+ zookeeper.create(path, date, acls, CreateMode.PERSISTENT);
+ } else {
+ logger.warn("Node already exists ! Don't need to create");
+ }
+ } catch (KeeperException | InterruptedException e) {
+ e.printStackTrace();
+ } finally {
+ closeConn();
+ }
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index 438ad76..e99e695 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,29 +7,6 @@
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
- <!--nexus中央仓库-->
- <repositories>
- <repository>
- <id>nexus</id>
- <name>Team Nexus Repository</name>
- <url>http://192.168.40.125:8099/content/groups/public</url>
- </repository>
- </repositories>
-
- <!--定义snapshots库和releases库的nexus地址-->
- <distributionManagement>
- <repository>
- <id>nexus-releases</id>
- <name>Nexus Release Repository</name>
- <url>http://192.168.40.125:8099/content/repositories/releases/</url>
- </repository>
- <snapshotRepository>
- <id>nexus-snapshots</id>
- <name>Nexus Snapshot Repository</name>
- <url>http://192.168.40.125:8099/content/repositories/snapshots/</url>
- </snapshotRepository>
- </distributionManagement>
-
<modules>
<!--查询网关-->
<module>galaxy-gateway</module>
@@ -51,21 +28,22 @@
<module>galaxy-job-core</module>
<!--数据查询引擎-->
<module>galaxy-query-engine</module>
+ <!--核心工具类库-->
+ <module>galaxy-tool</module>
</modules>
<properties>
<avro.version>1.9.1</avro.version>
<nutz.version>1.r.65</nutz.version>
<guava.version>23.0</guava.version>
- <groovy.version>2.5.9</groovy.version>
<log4j.version>2.10.0</log4j.version>
+ <groovy.version>2.5.9</groovy.version>
<hutool.version>5.4.0</hutool.version>
<lombok.version>1.18.6</lombok.version>
- <zdjizhi.version>1.0.4</zdjizhi.version>
<jakarta.version>3.0.0</jakarta.version>
<commonsio.version>2.2</commonsio.version>
- <fastjson.version>1.2.69</fastjson.version>
<joda.time.version>2.6</joda.time.version>
+ <fastjson.version>1.2.69</fastjson.version>
<jsqlparser.version>3.0</jsqlparser.version>
<jsqlparser.version>3.0</jsqlparser.version>
<httpclient.version>4.5.6</httpclient.version>
@@ -80,9 +58,10 @@
<maven.compiler.target>1.8</maven.compiler.target>
<commons.lang3.version>3.5</commons.lang3.version>
<hbase.client.version>2.2.3</hbase.client.version>
- <hadoop.client.version>2.7.1</hadoop.client.version>
<calcite.core.version>1.22.0</calcite.core.version>
<netty-all.version>4.1.50.Final</netty-all.version>
+ <hadoop.client.version>2.7.1</hadoop.client.version>
+ <aws-java-sdk.version>1.11.781</aws-java-sdk.version>
<active.record.version>4.9.01</active.record.version>
<starter.druid.version>1.1.22</starter.druid.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>