7 Commits

33 changed files with 2300 additions and 500 deletions

201
LICENSE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -7,23 +7,9 @@ gitee:https://gitee.com/jzsw-it/yexuejc-base
### 说明
1. 支持环境java81.5.0开始支持java11请使用`x.x.x-jre11`版本)
2. 该工具包基于springboot提取按理说适用于所有java工程
3. 其中依赖jjwt相关、validation-api排除请使用
> ```
> <exclusions>
> <exclusion>
> <artifactId>xxx</artifactId>
> <groupId>xxxx</groupId>
> </exclusion>
> </exclusions>
> ```
>
4. `1.1.9` 升级JWT为单例类
5. `1.2.3` 修复RSA加密(签名)Base64Url 问题如需使用RSA请使用1.2.3+
6.`1.3.0`开始,变更组织`groupId``top.yexuejc`。使用者请尽快升级到`1.3.0`以上1.3.0代码向下兼容)
7.`1.5.0`开始,版本分为`1.5.0-jre8``1.5.0-jre11`分别对于jre8和jre11使用
3. `1.5.0`开始,版本分为`1.5.0-jre8``1.5.0-jre11`分别对于jre8和jre11使用
### 使用
>yexuejc.base.version=1.5.0-jre8
pom.xml
```
@@ -31,30 +17,10 @@ pom.xml
<dependency>
<groupId>top.yexuejc</groupId>
<artifactId>yexuejc-base</artifactId>
<version>${yexuejc.base.version}</version>
<version>1.5.2-jre8</version>
</dependency>
</dependencies>
```
#### 附1.3.0之前的使用方式
pom.xml
```
<dependencies>
<dependency>
<groupId>com.yexuejc.base</groupId>
<artifactId>yexuejc-base</artifactId>
<version>1.3.0以下</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>yexuejc-nexus-public</id>
<name>yexuejc-nexus-public</name>
<url>https://nexus.yexuejc.club/repository/maven-public/</url>
</repository>
</repositories>
```
### 工具文档
[Wiki](WIKI.md)

View File

@@ -1,5 +1,34 @@
yexuejc-base 更新记录
------------------
#### version 1.5.3-jre8
**time ** <br/>
**branch** jre8 <br/>
**update** <br/>
1. [FileUtil.java](src/main/java/com/yexuejc/base/util/FileUtil.java)增加读取大文件自定义方法和单纯读取方法
2. 增加AES加解密: [com.yexuejc.base.encrypt.AES](src/main/java/com/yexuejc/base/encrypt/AES.java)
---
#### version 1.5.2-jre8
**time2024-4-7 14:34:33** <br/>
**branch** jre8 <br/>
**update** <br/>
1. 升级相关依赖
2. 依赖工具读取文件[FileInput.java](src/main/java/com/yexuejc/base/file/FileInput.java)从[FileUtil.java](src/main/java/com/yexuejc/base/util/FileUtil.java)中提取出来
3. 优化[FileUtil.java](src/main/java/com/yexuejc/base/util/FileUtil.java)
4. 优化[JwtUtil.java](src/main/java/com/yexuejc/base/util/JwtUtil.java)
---
#### version 1.5.1-jre8
**time2023-6-8 16:02:56** <br/>
**branch** jre11 <br/>
**update** <br/>
1. FileUtil 增加读取csv文件分页读取
提供读取IO流方法合集
2. 增加AES加解密
3. 增加文件压缩ZipUtil
4. DateUtilDateTimeUtil 时间操作工具优化
5. JsonUtil [feat] 增加json化时对LocalDateTime,LocalDate,Timestamp时间的优化,增加特殊场景序列化反序列化
#### version 1.5.0-jre8
**time2022-5-9 13:37:31** <br/>

60
pom.xml
View File

@@ -6,16 +6,16 @@
<groupId>top.yexuejc</groupId>
<artifactId>yexuejc-base</artifactId>
<version>1.5.0-jre8</version>
<version>1.5.2-jre8</version>
<name>${project.artifactId}</name>
<name>yexuejc-base</name>
<url>https://github.com/yexuejc/yexuejc-base</url>
<description>Common toolkits based on JDK8 packaging</description>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
@@ -40,17 +40,19 @@
<properties>
<repos.yexuejc.url>https://nexus.yexuejc.top/repository/</repos.yexuejc.url>
<repos.aliyun.url>http://maven.aliyun.com/nexus/content/groups/public</repos.aliyun.url>
<repos.aliyun.url>https://maven.aliyun.com/repository/public</repos.aliyun.url>
<repos.jitpack.url>https://jitpack.io</repos.jitpack.url>
<jjwt.version>0.11.5</jjwt.version>
<jjwt.version>0.12.5</jjwt.version>
<maven.compiler.verbose>true</maven.compiler.verbose>
<java.version>1.8</java.version>
<validation-api.version>3.0.1</validation-api.version>
<validation-api.version>3.0.2</validation-api.version>
<commons-io.version>2.11.0</commons-io.version>
<bcprov-jdk15on.version>1.70</bcprov-jdk15on.version>
<guava.version>31.1-jre</guava.version>
<apache-poi.version>5.2.2</apache-poi.version>
<bcprov-jdk18on.version>1.78</bcprov-jdk18on.version>
<guava.version>33.1.0-jre</guava.version>
<apache-poi.version>5.2.5</apache-poi.version>
<jackson.version>2.17.0</jackson.version>
<zip4j.version>2.11.4</zip4j.version>
<!-- 文件拷贝时的编码 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
@@ -91,14 +93,15 @@
<!--支持大量的密码术算法并提供JCE 1.2.1的实现-->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bcprov-jdk15on.version}</version>
<artifactId>bcprov-jdk18on</artifactId>
<version>${bcprov-jdk18on.version}</version>
</dependency>
<!--com.yexuejc.base.util.SysUtil.threadRun 异步处理代码-->
<!--com.yexuejc.base.file.FileInput 读文件-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
<optional>true</optional>
</dependency>
<dependency>
@@ -110,11 +113,34 @@
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${apache-poi.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>${zip4j.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
@@ -126,7 +152,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<version>3.13.0</version>
<configuration>
<encoding>UTF-8</encoding>
<source>8</source>
@@ -137,7 +163,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-sources</id>
@@ -196,12 +222,12 @@
</build>
<repositories>
<repository>
<id>yexuejc-nexus-public</id>
<id>yexuejc-maven</id>
<name>yexuejc-nexus-public</name>
<url>${repos.yexuejc.url}maven-public/</url>
</repository>
<repository>
<id>aliyun-nexus-public</id>
<id>aliyun-maven</id>
<name>aliyun-nexus-public</name>
<url>${repos.aliyun.url}</url>
</repository>

View File

@@ -0,0 +1,36 @@
package com.yexuejc.base.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 设置csv header
*
* @author MAXF-MAC
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface CsvToBean {
/**
* 在类头上设置csv格式的header
* csv文件和java bean的映射
*/
String header();
/**
* csv文件的分割符号
*/
char delimiter() default ',';
/**
* CSV文件是否有header
*/
boolean hasHeader() default false;
}

View File

@@ -1,4 +1,6 @@
package com.yexuejc.base.util;
package com.yexuejc.base.annotation;
import com.yexuejc.base.util.ObjUtil;
import java.lang.annotation.*;

View File

@@ -0,0 +1,21 @@
package com.yexuejc.base.constant;
/**
* @author yexuejc
* @class-name DateConsts
* @description
* @date 2023/05/17 13:45
*/
public class DateConsts {
public static final String BAR = "-";
public static final CharSequence DATE_KEY_AM = "AM";
public static final CharSequence DATE_KEY_PM = "PM";
public static final String DATE_TIMESTAMP_LINUX = "M/dd/yy, h:mm a";
public static final CharSequence SLASH = "/";
public static final CharSequence COLON = ":";
public static final String DATE_YYYY_MM_DD_SLASH = "yyyy/MM/dd";
public static final CharSequence DATE_KEY_T = "T";
public static final String DATE_KEY_Z = "Z";
public static final String DATE_TIMESTAMP = "yyyy/MM/dd H:m:s";
public static final String DATE_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
}

View File

@@ -0,0 +1,38 @@
package com.yexuejc.base.converter;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
/**
* 反序列化中内容为空时返回Integer为空
* <p>使用方式:@JsonDeserialize(using = IntegerNullValueDeserializer.class)</p>
* @author: yexuejc
* @date: 2024/4/15 18:08
*/
public class IntegerNullValueDeserializer extends StdScalarDeserializer<Integer> {
public IntegerNullValueDeserializer() {
super(Integer.class);
}
@Override
public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String value = p.getValueAsString();
if (isInteger(value)) {
return super._parseInteger(p, ctxt, Integer.class);
} else {
return null;
}
}
private static boolean isInteger(String s) {
try {
Integer.parseInt(s);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}

View File

@@ -0,0 +1,44 @@
package com.yexuejc.base.converter;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.yexuejc.base.constant.DateConsts;
import com.yexuejc.base.util.StrUtil;
/**
* json转LocalDate
*
* @author yexuejc
* @date 2022/10/08
*/
public class LocalDateDeserializer extends JsonDeserializer<LocalDate> {
@Override
public LocalDate deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException {
String timeString = jsonParser.getValueAsString();
if (StrUtil.isEmpty(timeString)) {
return null;
}
if (timeString.contains(DateConsts.BAR)) {
return LocalDate.parse(timeString, DateTimeFormatter.ISO_DATE);
} else if (timeString.contains(DateConsts.DATE_KEY_AM)
|| timeString.contains(DateConsts.DATE_KEY_PM)) {
return LocalDate.parse(timeString,
DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP_LINUX, Locale.ENGLISH));
} else if (timeString.contains(DateConsts.SLASH) && timeString.contains(DateConsts.COLON)) {
return LocalDate.parse(timeString.substring(0, 10),
DateTimeFormatter.ofPattern(DateConsts.DATE_YYYY_MM_DD_SLASH));
} else if (timeString.contains(DateConsts.SLASH)) {
return LocalDate.parse(timeString, DateTimeFormatter.ofPattern(DateConsts.DATE_YYYY_MM_DD_SLASH));
} else {
return LocalDate.parse(timeString, DateTimeFormatter.BASIC_ISO_DATE);
}
}
}

View File

@@ -0,0 +1,23 @@
package com.yexuejc.base.converter;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
/**
* localDate转json
*
* @author yexuejc
* @date 2022/10/08
*/
public class LocalDateSerializer extends JsonSerializer<LocalDate> {
@Override
public void serialize(LocalDate localDate, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeString(localDate.format(DateTimeFormatter.ISO_DATE));
}
}

View File

@@ -0,0 +1,44 @@
package com.yexuejc.base.converter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.yexuejc.base.constant.DateConsts;
import com.yexuejc.base.util.StrUtil;
/**
* json转LocalDateTime
*
* @author yexuejc
* @date 2022/10/08
*/
public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException {
String timeString = jsonParser.getValueAsString();
if (StrUtil.isEmpty(timeString)) {
return null;
}
if (timeString.contains(DateConsts.DATE_KEY_T)) {
return LocalDateTime.parse(timeString, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
} else if (timeString.contains(DateConsts.DATE_KEY_AM)
|| timeString.contains(DateConsts.DATE_KEY_PM)) {
return LocalDateTime.parse(timeString,
DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP_LINUX, Locale.ENGLISH));
} else if (timeString.endsWith(DateConsts.DATE_KEY_Z)) {
return LocalDateTime.parse(timeString, DateTimeFormatter.ISO_INSTANT);
} else if (timeString.contains(DateConsts.SLASH)) {
return LocalDateTime.parse(timeString, DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP));
} else {
return LocalDateTime.parse(timeString,
DateTimeFormatter.ofPattern(DateConsts.DATE_YYYY_MM_DD_HH_MM_SS));
}
}
}

View File

@@ -0,0 +1,23 @@
package com.yexuejc.base.converter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
/**
* LocalDateTime转json
*
* @author yexuejc
* @date 2022/10/08
*/
public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
@Override
public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
}
}

View File

@@ -0,0 +1,38 @@
package com.yexuejc.base.converter;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
/**
* <pre>
* json中的“”转String对象时值为null
* 例子:{str:""} ->
* JsonBean{
* public String str;
* }
* str的值为null [不使用{@link StringDeserializer},str的值为“”]
* </pre>
*
* <pre>
* 使用方式:
* jsonMapper.registerModule(new SimpleModule().addDeserializer(String.class, new StringDeserializer()));
* </pre>
*
* @author yexuejc
* @date 2022/10/08
*/
public class StringDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException {
String timeString = jsonParser.getValueAsString();
if ("".equals(timeString)) {
return null;
}
return timeString;
}
}

View File

@@ -0,0 +1,46 @@
package com.yexuejc.base.converter;
import java.io.IOException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.yexuejc.base.constant.DateConsts;
import com.yexuejc.base.util.StrUtil;
/**
* json转LocalDateTime
*
* @author yexuejc
* @date 2022/10/08
*/
public class TimestampDeserializer extends JsonDeserializer<Timestamp> {
@Override
public Timestamp deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException {
String timeString = jsonParser.getValueAsString();
if (StrUtil.isEmpty(timeString)) {
return null;
}
if (timeString.contains(DateConsts.DATE_KEY_T)) {
return Timestamp.valueOf(LocalDateTime.parse(timeString, DateTimeFormatter.ISO_LOCAL_DATE_TIME));
} else if (timeString.contains(DateConsts.DATE_KEY_AM)
|| timeString.contains(DateConsts.DATE_KEY_PM)) {
return Timestamp.valueOf(LocalDateTime.parse(timeString,
DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP_LINUX, Locale.ENGLISH)));
} else if (timeString.endsWith(DateConsts.DATE_KEY_Z)) {
return Timestamp.valueOf(LocalDateTime.parse(timeString, DateTimeFormatter.ISO_INSTANT));
} else if (timeString.contains(DateConsts.SLASH)) {
return Timestamp.valueOf(
LocalDateTime.parse(timeString, DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP)));
} else {
return Timestamp.valueOf(LocalDateTime.parse(timeString,
DateTimeFormatter.ofPattern(DateConsts.DATE_YYYY_MM_DD_HH_MM_SS)));
}
}
}

View File

@@ -0,0 +1,25 @@
package com.yexuejc.base.converter;
import java.io.IOException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.yexuejc.base.constant.DateConsts;
/**
* Timestamp转json
*
* @author yexuejc
* @date 2022/10/08
*/
public class TimestampSerializer extends JsonSerializer<Timestamp> {
@Override
public void serialize(Timestamp timestamp, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
SimpleDateFormat df = new SimpleDateFormat(DateConsts.DATE_TIMESTAMP);
jsonGenerator.writeString(df.format(timestamp));
}
}

View File

@@ -0,0 +1,179 @@
package com.yexuejc.base.encrypt;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* AES加解密
*
* @author maxf
* @class-name AES
* @description
* @date 2022/11/11 15:36
*/
public class AES {
public static AES builder() {
return Instace.aes;
}
private static class Instace {
private static AES aes = new AES();
}
public static final String AES_ALGORITHM = "AES";
/**
* 加密模式
*/
public static enum ALGORITHM {
//算法/模式/填充 16字节加密后数据长度 不满16字节加密后长度
//AES/CBC/NoPadding 16 不支持
AES_CBC_NoPadding("AES/CBC/NoPadding"),
//AES/CBC/PKCS5Padding 32 16
AES_CBC_PKCS5Padding("AES/CBC/PKCS5Padding"),
//AES/CBC/ISO10126Padding 32 16
AES_CBC_ISO10126Padding("AES/CBC/ISO10126Padding"),
//AES/CFB/NoPadding 16 原始数据长度
AES_CFB_NoPadding("AES/CFB/NoPadding"),
//AES/CFB/PKCS5Padding 32 16
AES_CFB_PKCS5Padding("AES/CFB/PKCS5Padding"),
//AES/CFB/ISO10126Padding 32 16
AES_CFB_ISO10126Padding("AES/CFB/ISO10126Padding"),
//AES/ECB/NoPadding 16 不支持
AES_ECB_NoPadding("AES/ECB/NoPadding"),
//AES/ECB/PKCS5Padding 32 16
AES_ECB_PKCS5Padding("AES/ECB/PKCS5Padding"),
//AES/ECB/ISO10126Padding 32 16
AES_ECB_ISO10126Padding("AES/ECB/ISO10126Padding"),
//AES/OFB/NoPadding 16 原始数据长度
AES_OFB_NoPadding("AES/OFB/NoPadding"),
//AES/OFB/PKCS5Padding 32 16
AES_OFB_PKCS5Padding("AES/OFB/PKCS5Padding"),
//AES/OFB/ISO10126Padding 32 16
AES_OFB_ISO10126Padding("AES/OFB/ISO10126Padding"),
//AES/PCBC/NoPadding 16 不支持
AES_PCBC_NoPadding("AES/PCBC/NoPadding"),
//AES/PCBC/PKCS5Padding 32 16
AES_PCBC_PKCS5Padding("AES/PCBC/PKCS5Padding"),
//AES/PCBC/ISO10126Padding 32 16
AES_PCBC_ISO10126Padding("AES/PCBC/ISO10126Padding");
public String name;
ALGORITHM(String name) {
this.name = name;
}
}
private ALGORITHM algorithm = ALGORITHM.AES_CBC_NoPadding;
private String key = "hj7x89H$yuBI0456";
private String iv = "NIfb&95GUY86Gfgh";
private Charset charset = StandardCharsets.UTF_8;
/**
* 加密
*
* @param data 明文
* @return 密文
* @Description AES算法加密明文
*/
public String encrypt(String data) throws Exception {
try {
Cipher cipher = Cipher.getInstance(algorithm.name);
int blockSize = cipher.getBlockSize();
byte[] dataBytes = data.getBytes(charset);
int plaintextLength = dataBytes.length;
if (plaintextLength % blockSize != 0) {
plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
}
byte[] plaintext = new byte[plaintextLength];
System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(charset), AES_ALGORITHM);
IvParameterSpec ivspec = null;
if (!algorithm.name.contains("ECB")) {
ivspec = new IvParameterSpec(iv.getBytes(charset));
}
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(plaintext);
return Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 解密
*
* @param data 密文
* @return 明文
* @Description AES算法解密密文
*/
public String decrypt(String data) throws Exception {
try {
byte[] encrypted = Base64.getDecoder().decode(data);
Cipher cipher = Cipher.getInstance(algorithm.name);
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(charset), AES_ALGORITHM);
IvParameterSpec ivspec = null;
if (!algorithm.name.contains("ECB")) {
ivspec = new IvParameterSpec(iv.getBytes(charset));
}
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] original = cipher.doFinal(encrypted);
return new String(original, charset).trim();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//
// public static void main(String[] args) throws Exception {
// String str = " 奥萨蒂 asd8阿斯顿8asd ";
// AES.builder().setAlgorithm(ALGORITHM.AES_CBC_ISO10126Padding);
// AES.builder().setKey("DEsx89H$yuBI0456");
// String encrypt = AES.builder().encrypt(str);
// System.out.println(encrypt);
// String decrypt = AES.builder().decrypt(encrypt);
// System.out.println(">>>" + decrypt + "<<<");
// }
public ALGORITHM getAlgorithm() {
return algorithm;
}
public AES setAlgorithm(ALGORITHM algorithm) {
this.algorithm = algorithm;
return this;
}
public String getKey() {
return key;
}
public AES setKey(String key) {
this.key = key;
return this;
}
public String getIv() {
return iv;
}
public AES setIv(String iv) {
this.iv = iv;
return this;
}
public Charset getCharset() {
return charset;
}
public AES setCharset(Charset charset) {
this.charset = charset;
return this;
}
}

View File

@@ -0,0 +1,61 @@
package com.yexuejc.base.pojo;
/**
* {@link com.yexuejc.base.annotation.CsvToBean}
* 读取csv文件用
* @author yexuejc
* @class-name CsvToBean
* @description
* @date 2023/6/6 18:15
*/
public class CsvToBean {
/**
* 在类头上设置csv格式的header
* csv文件和java bean的映射
*/
private String header;
/**
* csv文件的分割符号
*/
private char delimiter;
/**
* CSV文件是否有header
*/
private boolean hasHeader;
public CsvToBean(String header, char delimiter, boolean hasHeader) {
this.header = header;
this.delimiter = delimiter;
this.hasHeader = hasHeader;
}
public String getHeader() {
return header;
}
public CsvToBean setHeader(String header) {
this.header = header;
return this;
}
public char getDelimiter() {
return delimiter;
}
public CsvToBean setDelimiter(char delimiter) {
this.delimiter = delimiter;
return this;
}
public boolean hasHeader() {
return hasHeader;
}
public CsvToBean setHasHeader(boolean hasHeader) {
this.hasHeader = hasHeader;
return this;
}
}

View File

@@ -4,7 +4,6 @@ import com.yexuejc.base.util.JsonUtil;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
/**
* 分页 VO
*

View File

@@ -0,0 +1,125 @@
package com.yexuejc.base.pojo;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.function.Function;
/**
* @author maxf
* @class-name ReadFileBean
* @description 分段读取大文件
* @date 2022/5/16 21:53
*/
public class ReadFileBean<T> {
/**
* 开始行数
*/
private int startRowNum;
/**
* 结束行数
*/
private int endRowNum;
/**
* 每次读取的行数
*/
private int readRowNum;
/**
* 开始行到结束行的数据
*/
private List<T> datas;
/**
* 文件指针位置,默认0开始位置
*/
private long pointer = 0;
/**
* 文件的length
*/
private long fileLength;
/**
* csv文件存在header
*/
private String header;
private Charset readCharset = StandardCharsets.UTF_8;
public Function<String, String> lineScavenger = t -> t;
public ReadFileBean() {
this.readRowNum = Integer.MAX_VALUE;
this.startRowNum = 1;
this.endRowNum = 0;
}
public ReadFileBean(int readRow) {
this.readRowNum = readRow;
this.startRowNum = 1;
this.endRowNum = 0;
}
public Charset getReadCharset() {
return readCharset;
}
public ReadFileBean<T> setReadCharset(Charset readCharset) {
this.readCharset = readCharset;
return this;
}
public String getHeader() {
return header;
}
public ReadFileBean<T> setHeader(String header) {
this.header = header;
return this;
}
public int getReadRowNum() {
return readRowNum;
}
public int getStartRowNum() {
return startRowNum;
}
public int getEndRowNum() {
return endRowNum;
}
public List<T> getDatas() {
return datas;
}
public ReadFileBean<T> setDatas(List<T> datas) {
this.datas = datas;
this.startRowNum = this.endRowNum + 1;
this.endRowNum += this.readRowNum;
return this;
}
public long getPointer() {
return pointer;
}
public ReadFileBean<T> setPointer(long pointer) {
this.pointer = pointer;
return this;
}
public long getFileLength() {
return fileLength;
}
public ReadFileBean<T> setFileLength(long fileLength) {
this.fileLength = fileLength;
return this;
}
public String lineScavenge(String lineData) {
return this.lineScavenger.apply(lineData);
}
public boolean hasNext() {
return this.fileLength > this.pointer;
}
}

View File

@@ -1,11 +1,13 @@
package com.yexuejc.base.util;
import java.text.ParseException;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
/**
* 新版时间日期出来 工具
*
@@ -258,9 +260,19 @@ public class DateTimeUtil {
* @return
*/
public static LocalDateTime parseLocalDateTime13(long timestamp) {
return parseLocalDateTime13(timestamp, ZoneId.systemDefault());
}
/**
* Long 转 LocalDateTime
*
* @param timestamp 13位毫秒
* @param zoneId 时区
* @return
*/
public static LocalDateTime parseLocalDateTime13(long timestamp, ZoneId zoneId) {
Instant instant = Instant.ofEpochMilli(timestamp);
ZoneId zone = ZoneId.systemDefault();
return LocalDateTime.ofInstant(instant, zone);
return LocalDateTime.ofInstant(instant, zoneId);
}
/**
@@ -270,9 +282,32 @@ public class DateTimeUtil {
* @return
*/
public static LocalDateTime parseLocalDateTime10(long timestamp) {
return parseLocalDateTime10(timestamp, ZoneId.systemDefault());
}
/**
* Long 转 LocalDateTime
*
* @param timestamp 10位
* @param zoneId 时区
* @return
*/
public static LocalDateTime parseLocalDateTime10(long timestamp, ZoneId zoneId) {
Instant instant = Instant.ofEpochMilli(timestamp * 1000);
ZoneId zone = ZoneId.systemDefault();
return LocalDateTime.ofInstant(instant, zone);
return LocalDateTime.ofInstant(instant, zoneId);
}
/**
* UTC格林威治标准时间
*
* @param timestamp 13位毫秒/ 10位
* @return
*/
public static LocalDateTime parserUTC(Long timestamp) {
if (String.valueOf(timestamp).length() == 10) {
timestamp = timestamp * 1000;
}
return parseLocalDateTime13(timestamp, ZoneId.of("UTC"));
}
/**
@@ -299,6 +334,7 @@ public class DateTimeUtil {
return instant.toEpochMilli();
}
/**
* 格式化时间 <br/>
* 格式 yyyy-MM-dd HH:mm:ss
@@ -351,23 +387,71 @@ public class DateTimeUtil {
return df.format(dateTime);
}
/**
* 获取UTC格林威治标准时间
*
* @param date
* @return
*/
public static LocalDateTime convertUTC(LocalDateTime date) {
return convertTimezone(date, null, "UTC");
}
/** public static void main(String[] args) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(df.format(zonedDateTime2Date(ZonedDateTime.now())));
System.out.println(df2.format(date2ZonedDateTime(new Date())));
/**
* 时区转换(当前时区)
*
* @param date 时间
* @param zoneId 转换时区
* @return
*/
public static LocalDateTime convertTimezone(LocalDateTime date, String zoneId) {
return convertTimezone(date, null, zoneId);
}
System.out.println(getWeek4First());
System.out.println(format(getWeek4First(LocalDate.parse("2018-02-10")).atTime(LocalTime.MIN)));
System.out.println(format(getWeek4Last(LocalDate.parse("2018-02-10")).atTime(LocalTime.MAX)));
System.out.println(format(getMonth4First().atTime(LocalTime.MIN)));
System.out.println(format(getMonth4Last().atTime(LocalTime.MAX)));
/**
* 时区转换
*
* @param date 时间
* @param currentZoneId 当前时间的时区
* @param targetZoneId 转换时区
* @return
*/
public static LocalDateTime convertTimezone(LocalDateTime date, String currentZoneId, String targetZoneId) {
ZoneId currentZone;
if (currentZoneId == null) {
currentZone = ZoneId.systemDefault();
} else {
currentZone = ZoneId.of(currentZoneId);
}
ZoneId targetZone = ZoneId.of(targetZoneId);
return date.atZone(currentZone).withZoneSameInstant(targetZone).toLocalDateTime();
}
System.out.println(format(getYear4First().atTime(LocalTime.MIN)));
System.out.println(format(getYear4Last().atTime(LocalTime.MAX)));
}*/
/*public static void main(String[] args) throws ParseException {
System.out.println(parserUTC(1684140338161L));
System.out.println(convertUTC(LocalDateTime.now()));
Date date = DateUtil.str2dateTime("2023-05-15 08:28:05.327");
LocalDateTime localDateTime = parseLocalDateTime(date);
System.out.println(date);
System.out.println(localDateTime);
LocalDateTime utc = convertTimezone(localDateTime, "UTC", "Asia/Shanghai");
System.out.println(utc);
System.out.println(getWeek4First());
System.out.println(format(getWeek4First(LocalDate.parse("2018-02-10")).atTime(LocalTime.MIN)));
System.out.println(format(getWeek4Last(LocalDate.parse("2018-02-10")).atTime(LocalTime.MAX)));
System.out.println(format(getMonth4First().atTime(LocalTime.MIN)));
System.out.println(format(getMonth4Last().atTime(LocalTime.MAX)));
System.out.println(format(getYear4First().atTime(LocalTime.MIN)));
System.out.println(format(getYear4Last().atTime(LocalTime.MAX)));
System.out.println(parseLocalDateTime10(System.currentTimeMillis() / 1000));
System.out.println(parseLocalDateTime13(System.currentTimeMillis()));
}*/
}

View File

@@ -3,6 +3,7 @@ package com.yexuejc.base.util;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
@@ -58,8 +59,8 @@ public class DateUtil {
/**
* 比较两个日期大小
*
* @param date1
* @param date2
* @param date1 格式 yyyy-MM-dd
* @param date2 格式 yyyy-MM-dd
* @return date1>date2返回1;date1=date2返回0;date1<date2返回-1
* @throws ParseException
*/
@@ -191,4 +192,59 @@ public class DateUtil {
return calendar.getTime();
}
/**
* 获取UTC格林威治标准时间
*
* @param date
* @return
*/
public static Date convertUTC(Date date) {
return convertTimezone(date, null, "UTC");
}
/**
* 时区转换(当前时区)
*
* @param date 时间
* @param zoneId 转换时区
* @return
*/
public static Date convertTimezone(Date date, String zoneId) {
return convertTimezone(date, null, zoneId);
}
/**
* 时区转换
*
* @param date 时间
* @param currentZoneId 当前时间的时区
* @param targetZoneId 转换时区
* @return
*/
public static Date convertTimezone(Date date, String currentZoneId, String targetZoneId) {
ZoneId currentZone;
if (currentZoneId == null) {
currentZone = ZoneId.systemDefault();
} else {
currentZone = ZoneId.of(currentZoneId);
}
ZoneId targetZone = ZoneId.of(targetZoneId);
return Date.from(date.toInstant().atZone(currentZone).withZoneSameInstant(targetZone).toInstant());
}
/* public static void main(String[] args) throws ParseException {
System.out.println(DateUtil.currentDate());
System.out.println(DateUtil.currentTime());
System.out.println(DateUtil.currentDateTime());
System.out.println(DateUtil.dateCompare("2024-01-25","2025-01-01"));
System.out.println(DateUtil.str2date("2024-01-25"));
System.out.println(DateUtil.date2str(new Date()));
System.out.println(DateUtil.str2dateTime("2024-04-08 11:01:39.361"));
System.out.println(DateUtil.dateTime2str(new Date()));
System.out.println(DateUtil.getCurrentWeek(1));
System.out.println(DateUtil.dateMinus(DateUtil.datePlus(new Date(),50),new Date(),'M'));
System.out.println(DateUtil.convertUTC(new Date()));
System.out.println(DateUtil.convertTimezone(new Date(),"UTC","Asia/Shanghai"));
System.out.println(DateUtil.convertTimezone(new Date(),"UTC"));
}*/
}

View File

@@ -1,15 +1,35 @@
package com.yexuejc.base.util;
import java.io.*;
import java.math.BigInteger;
import java.nio.MappedByteBuffer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.CRC32;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import com.yexuejc.base.annotation.CsvToBean;
import com.yexuejc.base.pojo.ReadFileBean;
import io.jsonwebtoken.lang.Assert;
/**
* 文件工具类
*
@@ -19,12 +39,16 @@ import java.util.zip.CRC32;
* @time 2017年11月3日 下午3:12:49
*/
public class FileUtil {
static Logger logger = Logger.getLogger(FileUtil.class.getName());
private static final Logger logger = Logger.getLogger(FileUtil.class.getName());
private FileUtil() {
}
private static final String NEW_LINE = "\n";
private static final String CONSTANT_DOT = ".";
private static final String TYPE_TAR_GZ = ".tar.gz";
private static final String TYPE_CSV = ".csv";
private static final String TAR_GZ = "tar.gz";
/**
@@ -41,7 +65,7 @@ public class FileUtil {
if (fileName.lastIndexOf(TYPE_TAR_GZ) > 0) {
return TAR_GZ;
}
return fileName.substring(fileName.lastIndexOf(".") + 1);
return fileName.substring(fileName.lastIndexOf(CONSTANT_DOT) + 1);
} catch (Exception e) {
logger.severe("file doesn't exist or is not a file");
}
@@ -51,22 +75,38 @@ public class FileUtil {
/**
* 判断文件是否存在
*
* @param filePath
* @return false 文件不存在true 文件存在
*/
public static boolean isFileExist(String filePath) {
if (StrUtil.isEmpty(filePath)) {
return false;
}
File file = new File(filePath);
return file.exists() && !file.isDirectory();
}
/**
* 判断文件是否存在,不存在就创建一个空的
*
* @param file
*/
public static void judeFileExists(File file) {
if (file.exists()) {
logger.severe("file exists");
} else {
logger.info("file not exists, create it ...");
try {
file.createNewFile();
boolean b = file.createNewFile();
if (b) {
logger.info("file create success");
} else {
logger.severe("file create fail");
}
} catch (IOException e) {
logger.severe("file create fail");
e.printStackTrace();
logger.log(Level.WARNING, "file create fail", e);
}
}
}
/**
@@ -103,74 +143,10 @@ public class FileUtil {
* @return
*/
public static String sha1(File file) {
FileInputStream in = null;
try {
in = new FileInputStream(file);
MessageDigest digest = MessageDigest.getInstance("SHA-1");
byte[] buffer = new byte[1024 * 1024 * 10];
int len = 0;
while ((len = in.read(buffer)) > 0) {
digest.update(buffer, 0, len);
}
String sha1 = new BigInteger(1, digest.digest()).toString(16);
int length = 40 - sha1.length();
if (length > 0) {
for (int i = 0; i < length; i++) {
sha1 = "0" + sha1;
}
}
return sha1;
} catch (NoSuchAlgorithmException e) {
logger.severe("system algorithm error.");
e.printStackTrace();
} catch (FileNotFoundException e) {
logger.severe("file doesn't exist or is not a file");
e.printStackTrace();
} catch (IOException e) {
logger.severe("The operation file is an IO exception.");
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
logger.severe("close FileInputStream IO exception.");
}
}
return null;
return getDigest(file, "SHA-1");
}
/***
* 计算SHA1码
*
* @return String 适用于上G大的文件
* @throws NoSuchAlgorithmException
* */
public static String sha1ByBigFile(File file) {
MessageDigest messagedigest = null;
try {
messagedigest = MessageDigest.getInstance("SHA-1");
FileInputStream in = new FileInputStream(file);
FileChannel ch = in.getChannel();
MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
messagedigest.update(byteBuffer);
return StrUtil.toHex(messagedigest.digest());
} catch (NoSuchAlgorithmException e) {
logger.severe("system algorithm error.");
e.printStackTrace();
} catch (FileNotFoundException e) {
logger.severe("file doesn't exist or is not a file");
e.printStackTrace();
} catch (IOException e) {
logger.severe("The operation file is an IO exception.");
e.printStackTrace();
}
return null;
}
/**
* 文件md5
*
@@ -178,66 +154,40 @@ public class FileUtil {
* @return
*/
public static String md5(File file) {
FileInputStream in = null;
try {
in = new FileInputStream(file);
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] buffer = new byte[1024 * 1024 * 10];
int len = 0;
while ((len = in.read(buffer)) > 0) {
digest.update(buffer, 0, len);
}
String md5 = new BigInteger(1, digest.digest()).toString(16);
int length = 32 - md5.length();
if (length > 0) {
for (int i = 0; i < length; i++) {
md5 = "0" + md5;
}
}
return md5;
} catch (IOException e) {
logger.severe("The operation file is an IO exception.");
} catch (NoSuchAlgorithmException e) {
logger.severe("system algorithm error.");
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
logger.severe("close FileInputStream IO exception.");
}
}
return null;
return getDigest(file, "MD5");
}
/**
* 对一个文件获取md5
*
* @return md5串
* @throws NoSuchAlgorithmException
* 获取文件的散列
* @param file
* @param digestCode
* @return
*/
public static String md5ByBigFile(File file) {
MessageDigest messagedigest = null;
try {
messagedigest = MessageDigest.getInstance("MD5");
FileInputStream in = new FileInputStream(file);
FileChannel ch = in.getChannel();
MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0,
file.length());
messagedigest.update(byteBuffer);
return StrUtil.toHex(messagedigest.digest());
private static String getDigest(File file, String digestCode) {
try (FileInputStream in = new FileInputStream(file)) {
MessageDigest digest = MessageDigest.getInstance(digestCode);
FileChannel channel = in.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024); // 1MB 缓冲区
// 读取文件内容并更新 MessageDigest
while (channel.read(buffer) != -1) {
buffer.flip(); // 将 Buffer 从写模式切换到读模式
digest.update(buffer); // 更新 MessageDigest
buffer.clear(); // 清空 Buffer
}
// 计算最终的 SHA-1 散列值
byte[] sha1Bytes = digest.digest();
// 将字节数组转换为十六进制字符串
StringBuilder sha1Builder = new StringBuilder();
for (byte b : sha1Bytes) {
sha1Builder.append(String.format("%02x", b));
}
return sha1Builder.toString();
} catch (NoSuchAlgorithmException e) {
logger.severe("system algorithm error.");
e.printStackTrace();
logger.log(Level.SEVERE, "system algorithm error.", e);
} catch (FileNotFoundException e) {
logger.severe("file doesn't exist or is not a file");
e.printStackTrace();
logger.log(Level.SEVERE, "file doesn't exist or is not a file", e);
} catch (IOException e) {
logger.severe("The operation file is an IO exception.");
e.printStackTrace();
logger.log(Level.SEVERE, "The operation file is an IO exception.", e);
}
return null;
}
@@ -245,37 +195,24 @@ public class FileUtil {
/**
* 获取文件CRC32码
*
* @return String
* @return 获取失败返回-1
*/
public static String crc32(File file) {
public static long crc32(File file) {
CRC32 crc32 = new CRC32();
// MessageDigest.get
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
byte[] buffer = new byte[8192];
try (FileInputStream fileInputStream = new FileInputStream(file);) {
byte[] buffer = new byte[1024 * 1024];
int length;
while ((length = fileInputStream.read(buffer)) != -1) {
crc32.update(buffer, 0, length);
}
return crc32.getValue() + "";
return crc32.getValue();
} catch (FileNotFoundException e) {
logger.severe("file doesn't exist or is not a file");
e.printStackTrace();
return null;
logger.log(Level.SEVERE, "file doesn't exist or is not a file", e);
return -1;
} catch (IOException e) {
logger.severe("The operation file is an IO exception.");
e.printStackTrace();
return null;
} finally {
try {
if (fileInputStream != null) {
fileInputStream.close();
}
} catch (IOException e) {
logger.severe("close FileInputStream IO exception.");
e.printStackTrace();
}
logger.log(Level.SEVERE, "The operation file is an IO exception.", e);
return -1;
}
}
@@ -286,44 +223,27 @@ public class FileUtil {
* @return
*/
public static String base64ToStr(File file) {
return new String(base64(file));
}
/**
* 获取文件base64
*
* @param file
* @return
*/
public static byte[] base64(File file) {
FileInputStream fileInputStream = null;
byte[] data = null;
// 读取图片字节数组
try {
fileInputStream = new FileInputStream(file);
data = new byte[fileInputStream.available()];
fileInputStream.read(data);
fileInputStream.close();
byte[] bytes = Files.readAllBytes(Paths.get(file.getPath()));
return Base64.getEncoder().encodeToString(bytes);
} catch (IOException e) {
logger.severe("The operation file is an IO exception.");
e.printStackTrace();
}
// 对字节数组Base64编码
return Base64.getEncoder().encode(data);
return null;
}
/**
* base64转文件
* <p>
* <i>
* 文件转base64请使用 {@link FileUtil#base64(File)}
* 文件转base64请使用 {@link FileUtil#base64ToStr(File)}
* </i>
*
* @param decode {@link FileUtil#base64ToStr(File)} 的结果
* @param fileName 文件名称(包含路径)
* @return 返回保存地址
*/
public static String base64ToFile(String decode, String fileName) {
public static String base64ToFile(String decode, String fileName) throws IOException {
return base64ToFile(Base64.getDecoder().decode(decode.getBytes()), fileName);
}
@@ -331,29 +251,16 @@ public class FileUtil {
* base64转文件
* <p>
* <i>
* 文件转base64请使用 {@link FileUtil#base64(File)}
* 文件转base64请使用 {@link FileUtil#base64ToStr(File)}}
* </i>
*
* @param decode baseByte
* @param fileName 文件名称(包含路径)
* @return 返回保存地址
*/
public static String base64ToFile(byte[] decode, String fileName) {
FileOutputStream out = null;
try {
out = new FileOutputStream(fileName);
public static String base64ToFile(byte[] decode, String fileName) throws IOException {
try (FileOutputStream out = new FileOutputStream(fileName)) {
out.write(decode);
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return fileName;
}
@@ -361,12 +268,12 @@ public class FileUtil {
/**
* 获取文件大小 :直接返回大小
*
* @param f
* @param path 文件地址
* @return f.length()
*/
public static long size(File f) {
if (f.exists() && f.isFile()) {
return f.length();
public static long size(Path path) throws IOException {
if (Files.exists(path) && Files.isRegularFile(path)) {
return Files.size(path);
} else {
logger.info("file doesn't exist or is not a file");
}
@@ -374,67 +281,170 @@ public class FileUtil {
}
/**
* 获取文件大小 : 用流的方式获取
* 字符串csv格式转 对象
*
* @param f
* @param data 转换的字符串 如
* <p> ------------ </p>
* <p> id,name,age </p>
* <p> 1,zhangsan,18 </p>
* <p> 2,lisi,20 </p>
* <p> ------------ </p>
* @param cls 需要转换的对象,含有<b>id,name,age</b>字段
* @param delimiter 分隔符
* @param <I>
* @return
*/
public static long size4Stream(File f) {
FileChannel fc = null;
try {
if (f.exists() && f.isFile()) {
FileInputStream fis = new FileInputStream(f);
fc = fis.getChannel();
return fc.size();
} else {
logger.info("file doesn't exist or is not a file");
}
} catch (FileNotFoundException e) {
logger.severe("file doesn't exist or is not a file");
} catch (IOException e) {
logger.severe("The operation file is an IO exception.");
} finally {
if (null != fc) {
try {
fc.close();
} catch (IOException e) {
logger.severe("close FileInputStream IO exception.");
}
}
}
return 0;
public static <I> List<I> readCsv(String data, Class<I> cls, char delimiter) throws IOException {
CsvMapper csvMapper = new CsvMapper();
CsvSchema csvSchema = CsvSchema.emptySchema().withHeader().withColumnSeparator(delimiter);
MappingIterator<I> orderLines = csvMapper.readerFor(cls).with(csvSchema).readValues(data);
return orderLines.readAll();
}
/*public static void main(String[] args) {
long size = FileUtil.size(new File("E:\\OS\\deepin-15.6-amd64\\DeepinCloudPrintServerInstaller_1.0.0.1.exe"));
System.out.println(size);
System.out.println(1024 * 1024 * 5);
if (size > 1024 * 1024 * 5) {
System.out.println("文件最大5M");
return;
/**
* 读取csv文件
*
* @param csvFilePath 文件地址
* @param cls 读取转化的对象
* @param header 解析列对应的java字段用delimiter分割
* @param hasHeader csv文件中第一行是否是header
* @param delimiter 分隔符.默认【,】
* @param <I>
* @return
*/
public static <I> List<I> readCsv(final String csvFilePath, Class<I> cls, boolean hasHeader, String header, char delimiter) {
if (!isFileExist(csvFilePath)) {
throw new RuntimeException(String.format("解析用的csv [%s] 文件不存在。", csvFilePath));
}
if (StrUtil.isEmpty(delimiter)) {
delimiter = ',';
}
try {
File csvFile = new File(csvFilePath);
CsvMapper csvMapper = new CsvMapper();
CsvSchema.Builder builder = CsvSchema.builder();
if (StrUtil.isNotEmpty(header)) {
builder.addColumns(Arrays.asList(header.split(String.valueOf(delimiter))), CsvSchema.ColumnType.STRING);
}
CsvSchema csvSchema = builder.build().withColumnSeparator(delimiter).withSkipFirstDataRow(hasHeader).withStrictHeaders(hasHeader).withComments();
long s1 = fileSize(new File("E:\\OS\\cn_windows_10_consumer_editions_version_1803_updated_march_2018_x64_dvd_12063766.iso"));
System.out.println(s1);
long s2 = fileSize4Stream(new File("E:\\OS\\cn_windows_10_consumer_editions_version_1803_updated_march_2018_x64_dvd_12063766.iso"));
System.out.println(s2);
MappingIterator<I> recordIterator = csvMapper.readerWithTypedSchemaFor(cls).with(csvSchema).readValues(csvFile);
return recordIterator.readAll();
} catch (IOException e) {
throw new RuntimeException("[" + csvFilePath + "] 文件解析失败。", e);
}
}
String s1 = base64(new File("C:\\Users\\Administrator\\Desktop\\a.html"));
System.out.println(s1);
/**
* 分段读取大文件(不限格式)
*
* @param filePath 文件路径
* @param readFileBean 分段每次读取的bean 初始值需要设置每次读取的行数
* @param <T> 读取结果类型bean
* @return 文件分页读取内容(自定义处理后)及读取信息
*/
public static <T> ReadFileBean<T> readBigFile(String filePath, ReadFileBean<T> readFileBean, Function<List<String>, List<T>> readAfter) throws IOException {
if (!isFileExist(filePath)) {
throw new FileNotFoundException(String.format("[%s]文件不存在。", filePath));
}
List<String> datas = new ArrayList<>();
try (RandomAccessFile randomAccessFile = new RandomAccessFile(new File(filePath), "r")) {
if (readFileBean.getPointer() < 0) {
readFileBean.setPointer(0);
}
randomAccessFile.seek(readFileBean.getPointer());
readFileBean.setFileLength(randomAccessFile.length());
int row = 0;
String line;
while ((line = randomAccessFile.readLine()) != null && row <= readFileBean.getReadRowNum()) {
row++;
readFileBean.setPointer(randomAccessFile.getFilePointer());
datas.add(readFileBean.lineScavenge(charsetDecode(line, readFileBean.getReadCharset())));
}
}
if (StrUtil.isEmpty(datas)) {
//无数据
return readFileBean.setDatas(new ArrayList<>());
}
List<T> dataList = readAfter.apply(datas);
readFileBean.setDatas(dataList);
return readFileBean;
}
String s = sha1(new File("C:\\Users\\Administrator\\Desktop\\a.html"));
String s2 = sha1ByBigFile(new File("C:\\Users\\Administrator\\Desktop\\a.html"));
System.out.println(s);
System.out.println(s2);
/**
* 分段读取大文件(不解析)
*
* @param csvFilePath 文件路径
* @param readFileBean 分段每次读取的bean 初始值需要设置每次读取的行数
* @return 文件分页读取内容每行为一个String对象及读取信息
*/
public static ReadFileBean<String> readBigFile(String csvFilePath, ReadFileBean<String> readFileBean) throws IOException {
return readBigFile(csvFilePath, readFileBean, (datas) -> datas);
}
/**
* 分段读取大文件(CSV格式)
*
* @param csvFilePath 文件路径
* @param readFileBean 分段每次读取的bean 初始值需要设置每次读取的行数
* @param <T> 读取结果类型bean
* @return 文件分页读取内容转bean后及读取信息
*/
public static <T> ReadFileBean<T> readBigFile(String csvFilePath, ReadFileBean<T> readFileBean, Class<T> readCls) throws IOException {
if (!csvFilePath.endsWith(TYPE_CSV)) {
throw new IOException(String.format("[%s]文件不是CSV文件格式。", csvFilePath));
}
return readBigFile(csvFilePath, readFileBean, (datas) -> {
//csv文件处理
com.yexuejc.base.pojo.CsvToBean csvToBean = getCsvToBean(readCls);
readFileBean.setHeader(csvToBean.getHeader());
if (csvToBean.hasHeader()) {
//文件存在header,设置header优先,没设置使用文件的
if (StrUtil.isNotEmpty(csvToBean.getHeader())) {
//替换header
datas.remove(0);
datas.add(0, csvToBean.getHeader());
} else {
readFileBean.setHeader(datas.get(0));
}
} else {
//文件不存在header使用设置的
datas.add(0, csvToBean.getHeader());
}
try {
return readCsv(String.join(NEW_LINE, datas), readCls, csvToBean.getDelimiter());
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
String md5 = md5(new File("C:\\Users\\Administrator\\Desktop\\a.html"));
String md52 = md5ByBigFile(new File("C:\\Users\\Administrator\\Desktop\\a.html"));
System.out.println(md5);
System.out.println(md52);
/**
* 获取csv的header,使用注解{@link CsvToBean}
*
* @param cls
* @param <T>
* @return
*/
public static <T> com.yexuejc.base.pojo.CsvToBean getCsvToBean(Class<T> cls) {
CsvToBean annotation = cls.getAnnotation(CsvToBean.class);
Assert.notNull(annotation, cls + "类上需要添加注解@CsvToBean并指定header。");
return new com.yexuejc.base.pojo.CsvToBean(annotation.header(), annotation.delimiter(), annotation.hasHeader());
}
String crc32 = crc32(new File("C:\\Users\\Administrator\\Desktop\\a.html"));
System.out.println(crc32);
}*/
/**
* 把字符串data按照指定编码解码
*
* @param data 解码字符串
* @param charset 字符编码
* @return
*/
public static String charsetDecode(String data, Charset charset) {
char[] chars = data.toCharArray();
byte[] result = new byte[chars.length];
for (int i = 0; i < chars.length; i++) {
result[i] = (byte) chars[i];
}
return new String(result, charset);
}
}

View File

@@ -1,19 +1,37 @@
package com.yexuejc.base.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.TimeZone;
import java.util.logging.Logger;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.type.MapType;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.TimeZone;
import java.util.logging.Logger;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.yexuejc.base.converter.LocalDateDeserializer;
import com.yexuejc.base.converter.LocalDateSerializer;
import com.yexuejc.base.converter.LocalDateTimeDeserializer;
import com.yexuejc.base.converter.LocalDateTimeSerializer;
import com.yexuejc.base.converter.TimestampDeserializer;
import com.yexuejc.base.converter.TimestampSerializer;
/**
* json工具类基于jackson
@@ -24,7 +42,7 @@ import java.util.logging.Logger;
* @date 2018/9/3 15:28
*/
public class JsonUtil {
private static Logger log = Logger.getLogger(JsonUtil.class.getName());
private static final Logger log = Logger.getLogger(JsonUtil.class.getName());
private JsonUtil() {
}
@@ -32,32 +50,103 @@ public class JsonUtil {
/**
* 作为单例全局使用
*/
private static ObjectMapper objectMapper = new ObjectMapper();
private static final JsonMapper jsonMapper = new JsonMapper();
static {
JsonUtil.initDefaultObjectMapper(JsonUtil.objectMapper);
JsonUtil.initDefaultObjectMapper(JsonUtil.jsonMapper);
}
/**
* 对时间的支持
*
* @param jsonMapper
*/
private static void setJavaTimeModule(ObjectMapper jsonMapper) {
//设置一下时区,可以和程序同步避免时区问题
jsonMapper.setTimeZone(TimeZone.getDefault());
jsonMapper.setDateFormat(DateUtil.DATE_TIME_FORMAT);
JavaTimeModule javaTime = new JavaTimeModule();
//java time 特殊处理
javaTime.addSerializer(LocalDate.class, new LocalDateSerializer());
javaTime.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
javaTime.addSerializer(Timestamp.class, new TimestampSerializer());
javaTime.addDeserializer(LocalDate.class, new LocalDateDeserializer());
javaTime.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
javaTime.addDeserializer(Timestamp.class, new TimestampDeserializer());
jsonMapper.registerModule(javaTime);
}
/**
* 初始化ObjectMapper为默认属性
* <pre>
* 1.序列化值为空时NON_NULL舍去字段
* 2.JsonParser.Feature.ALLOW_SINGLE_QUOTES解析JSON时允许使用单引号')作为字符串的引号(true)
* 例子:{'localDateTime':'2023-05-29T15:32:03.9770447'}
* 3.JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES解析JSON时允许不使用引号作为字符串的引号(true)
* 例子:{age:12};适用于基本数据类型
* 4.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIESjson对应java Bean,数据字段对不齐的情况下不报错(false)
* 5.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS(false):用于指定是否将日期类型序列化为时间戳格式。如果启用该特性则日期类型将被序列化为Unix时间戳即从1970年1月1日00:00:00 GMT开始的毫秒数。如果禁用该特性则日期类型将以其原始格式进行序列化。
* 例子(false)"timestamp": "2020-07-08T02:02:55.000+00:00"
* 例子(true)"timestamp": 1594236175000
* </pre>
*
* @param objectMapper
* @param jsonMapper
* @return
*/
private static void initDefaultObjectMapper(ObjectMapper objectMapper) {
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//设置一下时区,可以和程序同步避免时区问题
objectMapper.setTimeZone(TimeZone.getDefault());
objectMapper.setDateFormat(DateUtil.DATE_TIME_FORMAT);
private static ObjectMapper initDefaultObjectMapper(ObjectMapper jsonMapper) {
JsonUtil.setJavaTimeModule(jsonMapper);
//值为空时NON_NULL舍去字段ALWAYS:保留字段
jsonMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
jsonMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
jsonMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
jsonMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
return jsonMapper;
}
/**
* 初始化ObjectMapper的默认属性
* <pre>
* 1.序列化值为空时ALWAYS:保留字段,值为“”
* 2.JsonParser.Feature.ALLOW_SINGLE_QUOTES解析JSON时允许使用单引号')作为字符串的引号(true)
* 例子:{'localDateTime':'2023-05-29T15:32:03.9770447'}
* 3.JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES解析JSON时允许不使用引号作为字符串的引号(true)
* 例子:{age:12};适用于基本数据类型
* 4.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIESjson对应java Bean,数据字段对不齐的情况下不报错(false)
* 5.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS(false):用于指定是否将日期类型序列化为时间戳格式。如果启用该特性则日期类型将被序列化为Unix时间戳即从1970年1月1日00:00:00 GMT开始的毫秒数。如果禁用该特性则日期类型将以其原始格式进行序列化。
* 例子(false)"timestamp": "2020-07-08T02:02:55.000+00:00"
* 例子(true)"timestamp": 1594236175000
* 6.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT反序列化值为空时映射到java Bean 非字符串类型值为null
* </pre>
*
* @return
*/
public static ObjectMapper acceptEmptyStringAsNullObject(JsonMapper jsonMapper) {
setJavaTimeModule(jsonMapper);
//值为空时ALWAYS:保留字段默认字符串值为“”对象值为null
jsonMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
jsonMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
jsonMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
jsonMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
jsonMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
//值为空时,序列化所有值为“”
jsonMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString("");
}
});
return jsonMapper;
}
//TODO 待优化
public static void initSnakeCase() {
//驼峰下划线互转
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
jsonMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
}
/**
@@ -86,8 +175,8 @@ public class JsonUtil {
*
* @return
*/
public static ObjectMapper getObjectMapper() {
return objectMapper;
public static ObjectMapper getJsonMapper() {
return jsonMapper;
}
/**
@@ -101,13 +190,13 @@ public class JsonUtil {
T pojo = null;
try {
pojo = objectMapper.readValue(json, cls);
pojo = jsonMapper.readValue(json, cls);
} catch (JsonParseException e) {
log.warning("json to Object JsonParseException.\n" + e.getMessage());
log.warning("json to Object JsonParseException.\n" + e);
} catch (JsonMappingException e) {
log.warning("json to Object JsonMappingException.\n" + e.getMessage());
log.warning("json to Object JsonMappingException.\n" + StrUtil.printStackTrace(e));
} catch (IOException e) {
log.warning("json to Object IOException.\n" + e.getMessage());
log.warning("json to Object IOException.\n" + StrUtil.printStackTrace(e));
}
return pojo;
@@ -123,15 +212,15 @@ public class JsonUtil {
public static <T> T json2Obj(String json, Class<T> cls) {
T pojo = null;
try {
pojo = objectMapper.readValue(json, cls);
pojo = jsonMapper.readValue(json, cls);
} catch (JsonParseException e) {
log.warning("json to Object JsonParseException.\n" + e.getMessage());
log.warning("json to Object JsonParseException.\n" + StrUtil.printStackTrace(e));
} catch (JsonMappingException e) {
log.warning("json to Object JsonMappingException.\n" + e.getMessage());
log.warning("json to Object JsonMappingException.\n" + StrUtil.printStackTrace(e));
} catch (IOException e) {
log.warning("json to Object IOException.\n" + e.getMessage());
log.warning("json to Object IOException.\n" + StrUtil.printStackTrace(e));
} catch (Exception e) {
e.printStackTrace();
log.warning("json to Object Exception.\n" + StrUtil.printStackTrace(e));
}
return pojo;
@@ -147,15 +236,15 @@ public class JsonUtil {
*/
public static <T> T json2Obj(String json, Class<T> parametrized, Class<?>... parameterClasses) {
T pojo = null;
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(parametrized, parameterClasses);
JavaType javaType = jsonMapper.getTypeFactory().constructParametricType(parametrized, parameterClasses);
try {
pojo = objectMapper.readValue(json, javaType);
pojo = jsonMapper.readValue(json, javaType);
} catch (JsonParseException e) {
log.warning("json to Object JsonParseException.\n" + e.getMessage());
log.warning("json to Object JsonParseException.\n" + StrUtil.printStackTrace(e));
} catch (JsonMappingException e) {
log.warning("json to Object JsonMappingException.\n" + e.getMessage());
log.warning("json to Object JsonMappingException.\n" + StrUtil.printStackTrace(e));
} catch (IOException e) {
log.warning("json to Object IOException.\n" + e.getMessage());
log.warning("json to Object IOException.\n" + StrUtil.printStackTrace(e));
}
return pojo;
}
@@ -172,15 +261,15 @@ public class JsonUtil {
*/
public static <T> T json2Obj(String json, Class<? extends Map> mapClass, Class<?> keyClass, Class<?> valueClass) {
T pojo = null;
MapType mapType = objectMapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass);
MapType mapType = jsonMapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass);
try {
pojo = objectMapper.readValue(json, mapType);
pojo = jsonMapper.readValue(json, mapType);
} catch (JsonParseException e) {
log.warning("json to Object JsonParseException.\n" + e.getMessage());
log.warning("json to Object JsonParseException.\n" + StrUtil.printStackTrace(e));
} catch (JsonMappingException e) {
log.warning("json to Object JsonMappingException.\n" + e.getMessage());
log.warning("json to Object JsonMappingException.\n" + StrUtil.printStackTrace(e));
} catch (IOException e) {
log.warning("json to Object IOException.\n" + e.getMessage());
log.warning("json to Object IOException.\n" + StrUtil.printStackTrace(e));
}
return pojo;
}
@@ -195,9 +284,9 @@ public class JsonUtil {
*/
public static <T extends Object> T json2Obj(String json, TypeReference<T> javaType) {
try {
return objectMapper.readValue(json, javaType);
return jsonMapper.readValue(json, javaType);
} catch (JsonProcessingException e) {
log.warning("json to Object JsonParseException.\n" + e.getMessage());
log.warning("json to Object JsonParseException.\n" + StrUtil.printStackTrace(e));
}
return null;
}
@@ -212,16 +301,16 @@ public class JsonUtil {
*/
public static <T> T json2Obj(InputStream json, Class<T> parametrized, Class<?>... parameterClasses) {
T pojo = null;
JavaType javaType = objectMapper.getTypeFactory().constructParametrizedType(parametrized, parametrized,
JavaType javaType = jsonMapper.getTypeFactory().constructParametrizedType(parametrized, parametrized,
parameterClasses);
try {
pojo = objectMapper.readValue(json, javaType);
pojo = jsonMapper.readValue(json, javaType);
} catch (JsonParseException e) {
log.warning("json to Object JsonParseException.\n" + e.getMessage());
log.warning("json to Object JsonParseException.\n" + StrUtil.printStackTrace(e));
} catch (JsonMappingException e) {
log.warning("json to Object JsonMappingException.\n" + e.getMessage());
log.warning("json to Object JsonMappingException.\n" + StrUtil.printStackTrace(e));
} catch (IOException e) {
log.warning("json to Object IOException.\n" + e.getMessage());
log.warning("json to Object IOException.\n" + StrUtil.printStackTrace(e));
}
return pojo;
}
@@ -235,9 +324,9 @@ public class JsonUtil {
public static String obj2Json(Object pojo) {
String json = null;
try {
json = objectMapper.writeValueAsString(pojo);
json = jsonMapper.writeValueAsString(pojo);
} catch (JsonProcessingException e) {
log.warning("json to Object JsonProcessingException.\n" + e.getMessage());
log.warning("json to Object JsonProcessingException.\n" + StrUtil.printStackTrace(e));
}
return json;
}
@@ -251,10 +340,11 @@ public class JsonUtil {
public static String formatPrinter(Object obj) {
String json = null;
try {
json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
json = jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (JsonProcessingException e) {
log.warning("json to Object JsonProcessingException.\n" + e.getMessage());
log.warning("json to Object JsonProcessingException.\n" + StrUtil.printStackTrace(e));
}
return json;
}
}

View File

@@ -1,10 +1,12 @@
package com.yexuejc.base.util;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;
import javax.crypto.SecretKey;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
/**
* jwt工具类
@@ -34,7 +36,7 @@ public class JwtUtil {
*
* @param key 加密key 默认h%OG8Y3WgA5AN7&6Ke7I#C1XvneW0N8a
* @param type 加密类型默认JWT
* @param iss token发行商: 默认yexuejc.com
* @param iss token发行商: 默认yexuejc.top
* @return
*/
public static JwtUtil config(String key, String type, String iss) {
@@ -60,7 +62,7 @@ public class JwtUtil {
/**
* token发行商
*/
private String JWT_CLAIMS_ISS = "yexuejc.com";
private String JWT_CLAIMS_ISS = "yexuejc.top";
/**
* 加密内容生成token
@@ -76,22 +78,22 @@ public class JwtUtil {
subject = JsonUtil.obj2Json(subjectObj);
}
Date now = new Date();
String token = Jwts.builder()
return Jwts.builder()
// 设置token的唯一标识IDclaims.jti
.setId(StrUtil.genUUID())
.id(StrUtil.genUUID())
// 设置token类型header.typ
.setHeaderParam("typ", JWT_HEADER_TYP)
.header().add("typ", JWT_HEADER_TYP)
.and()
// 设置token发行时间为当前时间claims.iat
.setIssuedAt(now)
.issuedAt(now)
// 设置token发行商/发行者claims.iss
.setIssuer(JWT_CLAIMS_ISS)
.issuer(JWT_CLAIMS_ISS)
// 设置token用户定义主体claims.sub
.setSubject(subject)
// 设置签名算法和KEYsignature
.signWith(SignatureAlgorithm.HS512, JWT_SIGNATURE_KEY)
.subject(subject)
// 设置算法签名,(密钥,加密算法)
.signWith(getSecretKey(), Jwts.SIG.HS512)
// 生成token
.compact();
return token;
}
/**
@@ -112,18 +114,8 @@ public class JwtUtil {
* @return
*/
public <T> T parse(String token, Class<T> cls) {
String subject = null;
try {
subject = Jwts.parser().setSigningKey(JWT_SIGNATURE_KEY).parseClaimsJws(token).getBody().getSubject();
} catch (Exception e) {
e.printStackTrace();
return JsonUtil.json2Obj(parseStr(token), cls);
}
if (subject == null) {
return null;
}
return JsonUtil.json2Obj(subject, cls);
}
/**
* 解密token为字符串
*
@@ -131,12 +123,11 @@ public class JwtUtil {
* @return
*/
public String parseStr(String token) {
String subject = null;
try {
subject = Jwts.parser().setSigningKey(JWT_SIGNATURE_KEY).parseClaimsJws(token).getBody().getSubject();
} catch (Exception e) {
e.printStackTrace();
return Jwts.parser().verifyWith(getSecretKey()).build().parseSignedClaims(token).getPayload().getSubject();
}
return subject;
private SecretKey getSecretKey() {
byte[] bytes = Decoders.BASE64.decode(JWT_SIGNATURE_KEY);
return Keys.hmacShaKeyFor(bytes);
}
}

View File

@@ -1,10 +1,16 @@
package com.yexuejc.base.util;
import com.yexuejc.base.annotation.ToUeProperty;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* 对象工具:对类的操作
@@ -16,6 +22,8 @@ import java.util.*;
* @date 2018/12/28 15:54
*/
public class ObjUtil {
private static Logger log = Logger.getLogger(ObjUtil.class.getName());
private ObjUtil() {
}
@@ -258,4 +266,150 @@ public class ObjUtil {
return outer;
}
/**
* 复制对象属性值,包含父类 (不需要getter和setter)
* <p>includeField和excludeField同时传入走包含逻辑</p>
*
* @param source 源对象
* @param targetClass 目标对象class
* @param includeField 包含对象
* @param excludeField 排除对象
* @param <I>
* @param <O>
* @return 目标对象
* @throws Exception
*/
public static <I, O> O copy(I source, Class<O> targetClass, List<String> includeField, List<String> excludeField) throws Exception {
List<Field> allFields = getAllFields(source.getClass());
O o = targetClass.getDeclaredConstructor().newInstance();
if (StrUtil.isNotEmpty(excludeField) && StrUtil.isEmpty(includeField)) {
allFields = allFields.stream().filter(f -> !excludeField.contains(f.getName())).collect(Collectors.toList());
}
if (StrUtil.isNotEmpty(includeField)) {
allFields = allFields.stream().filter(f -> includeField.contains(f.getName())).collect(Collectors.toList());
}
allFields.forEach(f -> {
try {
try {
Field field = targetClass.getDeclaredField(f.getName());
if (field != null) {
f.setAccessible(true);
Object v = f.get(source);
f.setAccessible(false);
field.setAccessible(true);
field.set(o, v);
field.setAccessible(false);
}
} catch (NoSuchFieldException e) {
}
} catch (Exception e) {
log.warning(lowerCaseFirstChar(f.getName()) + " field copy failed. " + e);
log.log(Level.FINER, lowerCaseFirstChar(f.getName()) +
" field copy failed. The exception information is as follows:", e);
}
});
return o;
}
/**
* 深度复制对象
* <p>获取source的所有getXxx。xxx作为属性且包含父类的getXxx</p>
* <p>查找target的xxx属性进行反射设值</p>
*
* @param source 源对象
* @param targetClass 目标对象class
* @param invokeSetter 设置target属性值时是否使用setter方法设置
* @param <I>
* @param <O>
* @return 目标对象
*/
public static <I, O> O copy(I source, Class<O> targetClass, boolean invokeSetter) throws Exception {
List<Method> getterMethods = getAllGetterMethods(source.getClass(), "get");
O o = targetClass.getDeclaredConstructor().newInstance();
getterMethods.forEach(method -> {
String fieldName = method.getName().replace("get", "");
try {
Object v = method.invoke(source);
if (invokeSetter) {
try {
Method setterMethod = targetClass.getDeclaredMethod("set" + fieldName, method.getReturnType());
if (null != setterMethod) {
setterMethod.invoke(o, v);
}
} catch (NoSuchMethodException e) {
}
} else {
try {
Field field = targetClass.getDeclaredField(lowerCaseFirstChar(fieldName));
if (field != null) {
field.setAccessible(true);
field.set(o, v);
field.setAccessible(false);
}
} catch (NoSuchFieldException e) {
}
}
} catch (Exception e) {
log.warning(lowerCaseFirstChar(fieldName) + " field copy failed. " + e);
log.log(Level.FINER, lowerCaseFirstChar(fieldName) +
" field copy failed. The exception information is as follows:\n", e);
}
});
return o;
}
/**
* 获取所有方法,包含父类
*
* @param beanClass
* @param startsWith 方法的开头匹配(空,返回所有)
* @return
*/
public static List<Method> getAllGetterMethods(Class<?> beanClass, String startsWith) {
List<Method> methodList = new ArrayList<>();
Method[] methods = beanClass.getDeclaredMethods();
if (StrUtil.isNotEmpty(startsWith)) {
methodList.addAll(Arrays.stream(methods)
.filter(method -> method.getName().startsWith(startsWith))
.collect(Collectors.toList()));
} else {
methodList.addAll(Arrays.asList(methods));
}
Class<?> superclass = beanClass.getSuperclass();
if (superclass != null) {
methodList.addAll(getAllGetterMethods(superclass, startsWith));
}
return methodList;
}
/**
* 获取所有属性,包含父类
*
* @param beanClass
* @return
*/
public static List<Field> getAllFields(Class<?> beanClass) {
List<Field> fieldList = new ArrayList<>();
while (beanClass != null) {
fieldList.addAll(Arrays.asList(beanClass.getDeclaredFields()));
beanClass = beanClass.getSuperclass();
}
return fieldList;
}
/**
* 首字母小写
*
* @param str
* @return
*/
public static String lowerCaseFirstChar(String str) {
if (str == null || str.length() == 0) {
return str;
} else {
return str.substring(0, 1).toLowerCase() + str.substring(1);
}
}
}

View File

@@ -1,9 +1,19 @@
package com.yexuejc.base.util;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -19,39 +29,28 @@ public final class StrUtil {
private StrUtil() {
}
public static char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* 判断字符串,数组,集合 是否为空
* 判断字符串,数组,集合 是否为空(null""[],{})
*
* @param obj
* @param obj 対象
* @return true:空;false:非空
* @return
*/
public static boolean isEmpty(Object obj) {
if (obj instanceof String) {
if (obj == null || "".equals((String) obj)) {
return true;
} else {
return false;
}
} else if (obj instanceof Object[]) {
if (obj == null || ((Object[]) obj).length == 0) {
return true;
} else {
return false;
}
} else if (obj instanceof Collection<?>) {
if (obj == null || ((Collection<?>) obj).size() == 0) {
return true;
} else {
return false;
}
if (obj == null) {
return true;
} else if (obj instanceof Optional) {
return !((Optional<?>) obj).isPresent();
} else if (obj instanceof CharSequence) {
return ((CharSequence) obj).length() == 0;
} else if (obj.getClass().isArray()) {
return Array.getLength(obj) == 0;
} else if (obj instanceof Collection) {
return ((Collection<?>) obj).isEmpty();
} else {
if (obj == null) {
return true;
} else {
return false;
}
return obj instanceof Map && ((Map<?, ?>) obj).isEmpty();
}
}
@@ -80,12 +79,12 @@ public final class StrUtil {
} else if (length < 1) {
return "";
} else {
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length / 32; i++) {
sb.append(genUUID());
}
if (length % 32 > 0) {
sb.append(genUUID().substring(0, length % 32));
sb.append(genUUID(), 0, length % 32);
}
return sb.toString();
}
@@ -101,48 +100,14 @@ public final class StrUtil {
*/
public static String genNum() {
int hashCode = UUID.randomUUID().toString().hashCode();
StringBuffer num = new StringBuffer();
StringBuilder num = new StringBuilder();
if (hashCode < 0) {
hashCode = 0 - hashCode;
hashCode = -hashCode;
num.append("0");
} else {
num.append("1");
}
return num.append(String.format("%010d", hashCode)).toString().substring(0, 8);
}
/**
* 解析aa=bb&cc=dd&ee=ff格式的字符串返回HashMap
*
* @param urlencoded
* @return
*/
public static Map<String, String> parseUrlencoded(String urlencoded) {
if (isEmpty(urlencoded)) {
return null;
}
String[] entrys = urlencoded.split("&");
if (isEmpty(entrys)) {
return null;
}
Map<String, String> map = new HashMap<String, String>(16);
String[] kv = null;
for (String entry : entrys) {
if (isEmpty(entry)) {
continue;
}
kv = entry.split("=");
if (isEmpty(kv)) {
continue;
}
if (kv.length > 1) {
map.put(kv[0], kv[1]);
} else {
map.put(kv[0], null);
}
}
return map;
return num.append(String.format("%010d", hashCode)).substring(0, 8);
}
/**
@@ -152,15 +117,15 @@ public final class StrUtil {
* @return 转换后字符串
*/
public static String toHex(byte[] buf) {
StringBuffer strbuf = new StringBuffer(buf.length * 2);
StringBuilder sb = new StringBuilder(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10) {
strbuf.append("0");
sb.append("0");
}
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
sb.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
return sb.toString();
}
/**
@@ -227,11 +192,7 @@ public final class StrUtil {
*/
public static String iso2utf(String str) {
String utfStr = null;
try {
utfStr = new String(str.getBytes("ISO-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
utfStr = new String(str.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
return utfStr;
}
@@ -241,21 +202,18 @@ public final class StrUtil {
* @param str
* @return
*/
private static Pattern pattern = Pattern.compile("[0-9]*");
private static final Pattern pattern = Pattern.compile("[0-9]*");
public static boolean isNumeric(String str) {
Matcher isNum = pattern.matcher(str);
if (!isNum.matches()) {
return false;
}
return true;
return isNum.matches();
}
/**
* 对ID32位进行编码
*
* @param id
* @return
* @param id 32位ID
* @return 编码后的64位ID
*/
public static String codeId(String id) {
if (id == null || id.length() != 32) {
@@ -267,7 +225,7 @@ public final class StrUtil {
for (int i = 0; i < 13; i++) {
coded.append(HEX_CHAR[random.nextInt(16)]);
}
coded.append(id.substring(0, 11));
coded.append(id, 0, 11);
for (int i = 0; i < 7; i++) {
coded.append(HEX_CHAR[random.nextInt(16)]);
}
@@ -282,8 +240,8 @@ public final class StrUtil {
/**
* 对ID32位进行解码
*
* @param coded
* @return
* @param coded 编码后的64位ID
* @return 解码后的32位ID
*/
public static String decodeId(String coded) {
if (coded == null || coded.length() != 64) {
@@ -291,12 +249,46 @@ public final class StrUtil {
}
StringBuilder id = new StringBuilder();
id.append(coded.substring(13, 24));
id.append(coded.substring(31, 52));
id.append(coded, 13, 24);
id.append(coded, 31, 52);
return id.toString();
}
/**
* 解析aa=bb&cc=dd&ee=ff格式的字符串返回HashMap
*
* @param urlencoded
* @return
*/
public static Map<String, String> parseUrlencoded(String urlencoded) {
if (isEmpty(urlencoded)) {
return null;
}
String[] entrys = urlencoded.split("&");
if (isEmpty(entrys)) {
return null;
}
Map<String, String> map = new HashMap<>(16);
String[] kv = null;
for (String entry : entrys) {
if (isEmpty(entry)) {
continue;
}
kv = entry.split("=");
if (isEmpty(kv)) {
continue;
}
if (kv.length > 1) {
map.put(kv[0], kv[1]);
} else {
map.put(kv[0], null);
}
}
return map;
}
/**
* map parameters 转url parameters
*
@@ -304,16 +296,15 @@ public final class StrUtil {
* @return
*/
public static String getSignContent(Map<String, ?> sortedParams) {
StringBuffer content = new StringBuffer();
StringBuilder content = new StringBuilder();
List<String> keys = new ArrayList<>(sortedParams.keySet());
Collections.sort(keys);
int index = 0;
for (int i = 0; i < keys.size(); ++i) {
String key = keys.get(i);
for (String key : keys) {
Object value = sortedParams.get(key);
if (isNotEmpty(key) && isNotEmpty(value)) {
content.append((index == 0 ? "" : "&") + key + "=" + value);
content.append(index == 0 ? "" : "&").append(key).append("=").append(value);
++index;
}
}
@@ -344,8 +335,7 @@ public final class StrUtil {
List<String> keys = new ArrayList<>(sortedParams.keySet());
Collections.sort(keys);
int index = 0;
for (int i = 0; i < keys.size(); ++i) {
String key = keys.get(i);
for (String key : keys) {
Object value = sortedParams.get(key);
map.put(key, value);
++index;
@@ -370,7 +360,7 @@ public final class StrUtil {
/**
* 下划线字符
*/
public static final char UNDERLINE = '_';
private static final char UNDERLINE = '_';
/**
* 字符串下划线转驼峰格式
@@ -419,4 +409,68 @@ public final class StrUtil {
}
return sb.toString();
}
private static final String NEW_LINE = "\n";
private static final String ERROR_MESSAGE_FORMAT = "%s.%s(%s:%d)";
/**
* 把异常堆栈信息转化为字符串,同时把所有的errorMessage用\n方式拼接到printStackTrace前面 -> 替代 e.printStackTrace()
* <p>使用e.printStackTrace()不能作为字符串处理本方法可以转换e.printStackTrace()为字符串</p>
* <p><b>printStackTrace</b>信息从<i>Caused by:</i>C开始</p>
*
* @param cause
* @return
*/
public static String printStackTraceAndMessage(Throwable cause) {
if (cause != null) {
StringBuilder msg = new StringBuilder();
if (isNotEmpty(cause.getMessage())) {
msg.append(cause.getMessage()).append(NEW_LINE);
}
String causedMsg = printStackTrace(cause, (eMessage) -> {
if (isNotEmpty(eMessage)) {
msg.append(eMessage).append(NEW_LINE);
}
});
return msg.append(causedMsg).toString();
}
return "";
}
/**
* 把异常堆栈信息转化为字符串 -> 替代 e.printStackTrace()
* <p>使用e.printStackTrace()不能作为字符串处理本方法可以转换e.printStackTrace()为字符串</p>
*
* @param cause
* @return
*/
public static String printStackTrace(Throwable cause) {
return printStackTrace(cause, (eMessage) -> {
});
}
private static String printStackTrace(Throwable cause, Consumer<String> consumer) {
if (cause != null) {
StringBuilder sb = new StringBuilder();
String cClass = cause.getClass().getName();
String eMessage = cause.getMessage();
StackTraceElement[] stackTrace = cause.getStackTrace();
Throwable caused = cause.getCause();
while (caused != null) {
cClass = caused.getClass().getName();
eMessage = caused.getMessage();
stackTrace = caused.getStackTrace();
caused = caused.getCause();
consumer.accept(eMessage);
}
sb.append("Caused by: ").append(cClass).append(": ").append(eMessage).append(NEW_LINE);
for (StackTraceElement element : stackTrace) {
sb.append("\tat ");
sb.append(String.format(ERROR_MESSAGE_FORMAT, element.getClassName(), element.getMethodName(), element.getFileName(), element.getLineNumber()));
sb.append(NEW_LINE);
}
return sb.toString();
}
return "";
}
}

View File

@@ -3,7 +3,15 @@ package com.yexuejc.base.util;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* 系统工具类
@@ -14,6 +22,7 @@ import java.util.concurrent.*;
* @date: 2017/12/28 16:12
*/
public class SysUtil {
private static final Logger logger = Logger.getLogger(SysUtil.class.getName());
private static final String PROJECT_ROOT_PATH = "java.io.tmpdir";
private SysUtil() {
@@ -34,8 +43,8 @@ public class SysUtil {
* @param clazz
* @return
*/
public static URL getRootPath(Class clazz, String filePath) {
return clazz.getClass().getResource(StrUtil.setStr(filePath, "/"));
public static URL getRootPath(Class<?> clazz, String filePath) {
return clazz.getResource(StrUtil.setStr(filePath, "/"));
}
/**
@@ -64,9 +73,7 @@ public class SysUtil {
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
singleThreadPool.execute(() -> {
threadRun.execute();
});
singleThreadPool.execute(threadRun::execute);
singleThreadPool.shutdown();
}
@@ -79,4 +86,116 @@ public class SysUtil {
*/
void execute();
}
/**
* 获取当前JVM所有线程
*
* @return
*/
public static List<Thread> getThreadList() {
List<Thread> threadList = new ArrayList<>();
ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();
while (currentGroup.getParent() != null) {
currentGroup = currentGroup.getParent();
}
int activeCount = currentGroup.activeCount();
Thread[] threads = new Thread[activeCount];
currentGroup.enumerate(threads);
for (Thread thread : threads) {
threadList.add(thread);
}
return threadList;
}
/** 线程锁 */
private static final Lock THREAD_LOCK = new ReentrantLock();
/** 已经等待的时间 */
private static final AtomicInteger SLEEP_TIME = new AtomicInteger(0);
/** 最大等待3分钟 */
private static final int MAX_SLEEP_TIME = 180;
/**
* 通过锁的方式判断jvm的内存如果超80%就等待最大3分钟JVM内存降低到80%再执行
*/
public static void checkJvmMemory() {
THREAD_LOCK.lock();
try {
while (jvmMemoryIsNotExecutable()) {
//jvm内存使用率达到80%,阻塞所有线程最大等待3分钟后放开
if (SLEEP_TIME.incrementAndGet() < MAX_SLEEP_TIME) {
TimeUnit.SECONDS.sleep(1);
} else {
break;
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
THREAD_LOCK.unlock();
SLEEP_TIME.set(0);
}
}
/**
* jvm内存是否大于80%(不能继续执行)
*
* @return true:是false:不是
*/
public static boolean jvmMemoryIsNotExecutable() {
Runtime runtime = Runtime.getRuntime();
//jvm总内存
long jvmTotalMemoryByte = runtime.totalMemory();
//jvm最大可申请
long jvmMaxMemoryByte = runtime.maxMemory();
//空闲空间
long freeMemoryByte = runtime.freeMemory();
double rate = (jvmTotalMemoryByte - freeMemoryByte) * 1.0 / jvmTotalMemoryByte;
if (rate >= 0.8) {
rate = (jvmTotalMemoryByte - freeMemoryByte) * 1.0 / jvmMaxMemoryByte;
if (rate >= 0.8) {
//jvm内存使用率达到80%
print(jvmTotalMemoryByte, jvmMaxMemoryByte, freeMemoryByte);
return true;
}
}
return false;
}
private static final DecimalFormat RATE_DECIMAL_FORMAT = new DecimalFormat("#.##%");
private static void print(long jvmTotalMemoryByte, long jvmMaxMemoryByte, long freeMemoryByte) {
if (logger.isLoggable(Level.WARNING)) {
String sb = "\n=========================================================" +
"\nThread Name = " + Thread.currentThread().getName() +
"\nJVM Memory = " + formatByte(jvmTotalMemoryByte) +
"\nJVM Max Memory = " + formatByte(jvmMaxMemoryByte) +
"\nJVM Used Memory = " + formatByte(jvmTotalMemoryByte - freeMemoryByte) +
"\nJVM Free Memory = " + formatByte(freeMemoryByte) +
"\nJVM Memory Rate = " + RATE_DECIMAL_FORMAT.format((jvmTotalMemoryByte - freeMemoryByte) * 1.0 / jvmTotalMemoryByte) +
"\n=========================================================";
logger.warning(sb);
}
}
private static String formatByte(long byteNumber) {
//换算单位
double format = 1024.0;
double kbNumber = byteNumber / format;
if (kbNumber < format) {
return new DecimalFormat("#.##KB").format(kbNumber);
}
double mbNumber = kbNumber / format;
if (mbNumber < format) {
return new DecimalFormat("#.##MB").format(mbNumber);
}
double gbNumber = mbNumber / format;
if (gbNumber < format) {
return new DecimalFormat("#.##GB").format(gbNumber);
}
double tbNumber = gbNumber / format;
return new DecimalFormat("#.##TB").format(tbNumber);
}
}

View File

@@ -0,0 +1,55 @@
package com.yexuejc.base.encrypt;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class AESTest {
@Test
public void testEncrypt() throws Exception {
String data = "Hello World!";
AES aes = AES.builder()
.setAlgorithm(AES.ALGORITHM.AES_CBC_PKCS5Padding)
.setKey("hj7x89H$yuBI0456")
.setIv("NIfb&95GUY86Gfgh")
.setCharset(StandardCharsets.UTF_8);
String encrypted = aes.encrypt(data);
assertNotNull(encrypted);
assertFalse(encrypted.isEmpty());
}
@Test
public void testDecrypt() throws Exception {
String data = "SGVsbG8gV29ybGQh";
AES aes = AES.builder()
.setAlgorithm(AES.ALGORITHM.AES_CBC_PKCS5Padding)
.setKey("hj7x89H$yuBI0456")
.setIv("NIfb&95GUY86Gfgh")
.setCharset(StandardCharsets.UTF_8);
String decrypted = aes.decrypt(data);
assertNotNull(decrypted);
assertFalse(decrypted.isEmpty());
assertEquals("Hello World!", decrypted);
}
@Test
public void testEncryptAndDecrypt() throws Exception {
String data = "张三";
AES aes = AES.builder()
.setAlgorithm(AES.ALGORITHM.AES_OFB_ISO10126Padding)
.setKey("hj7x89H$yuBI0456")
.setIv("NIfb&95GUY86Gfgh")
.setCharset(StandardCharsets.UTF_8);
String encrypt = aes.encrypt(data);
System.out.println("加密:" + encrypt);
String decrypt = aes.decrypt(encrypt);
System.out.println("解密:" + decrypt);
}
}

View File

@@ -0,0 +1,117 @@
package com.yexuejc.base.util;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import com.yexuejc.base.pojo.ReadFileBean;
import com.yexuejc.base.util.bean.AppnodeCertCsvBean;
/**
*
* @author: yexuejc
* @date: 2024/4/8 11:33
*/
public class FileUtilTest {
public static void main(String[] args) throws IOException {
readCsvFile();
// other();
}
private static void other() throws IOException {
System.out.println(FileUtil.getFileType("C:\\Users\\Administrator\\Desktop\\test.txt"));
boolean b = FileUtil.judeDirExists(new File("F:\\coding\\yexuejc-base2\\src\\test\\java\\com\\yexuejc\\base\\util\\test\\a"));
File file = new File("F:\\coding\\yexuejc-base2\\src\\test\\java\\com\\yexuejc\\base\\util\\test\\a\\test.txt");
FileUtil.judeFileExists(file);
System.out.println("创建文件夹:" + b);
System.out.println("SHA1:" + FileUtil.sha1(file));
//超大文件sha1
long l = System.currentTimeMillis();
System.out.println("SHA1:" + FileUtil.sha1(Paths.get("F:\\Docker\\win\\win10x64.iso").toFile()) + " 花费时间:" + (System.currentTimeMillis() - l));
System.out.println("MD5:" + FileUtil.md5(file));
//超大文件MD5
long l2 = System.currentTimeMillis();
System.out.println("MD5:" + FileUtil.md5(Paths.get("F:\\Docker\\win\\win10x64.iso").toFile()) + " 花费时间:" + (System.currentTimeMillis() - l2));
//超大文件MD5
long l3 = System.currentTimeMillis();
System.out.println("CRC32:" + FileUtil.crc32(Paths.get("F:\\Docker\\win\\win10x64.iso").toFile()) + " 花费时间:" + (System.currentTimeMillis() - l3));
String base64ToStr = FileUtil.base64ToStr(file);
System.out.println(base64ToStr);
String fileName = "F:\\coding\\yexuejc-base2\\src\\test\\java\\com\\yexuejc\\base\\util\\test\\a\\test2.txt";
System.out.println(FileUtil.base64ToFile(base64ToStr, fileName));
File file2 = Paths.get(fileName).toFile();
System.out.println("SHA1:" + FileUtil.sha1(file2));
System.out.println("MD5:" + FileUtil.md5(file2));
System.out.println(FileUtil.size(file2.toPath()));
long l4 = System.currentTimeMillis();
System.out.println(FileUtil.size(Paths.get("F:\\Docker\\win\\win10x64.iso")) + " 花费时间:" + (System.currentTimeMillis() - l4));
}
private static void readCsvFile() throws IOException {
String path = "F:\\coding\\yexuejc-base\\src\\test\\java\\com\\yexuejc\\base\\util\\test.csv";
// List<AppnodeCertCsvBean> list = FileUtil.readCsv(path, AppnodeCertCsvBean.class, true, "enable,domain,protocol,deployHost,deployPath,uname,pwd,appnodeId", ',');
// System.out.println("***********************************************");
// System.out.println(JsonUtil.formatPrinter(list));
// System.out.println("条数:" + list.size());
//直接把每行读取成字符串
ReadFileBean<String> readFileBean2 = new ReadFileBean<>(2);
ReadFileBean<String> bean2 = FileUtil.readBigFile(path, readFileBean2);
System.out.println("直接把每行读取成字符串============================================");
System.out.println(JsonUtil.formatPrinter(bean2));
System.out.println("直接把每行读取成字符串============================================");
//自定义每行数据的处理
ReadFileBean<AppnodeCertCsvBean> readFileBean1 = new ReadFileBean<>(2);
ReadFileBean<AppnodeCertCsvBean> bean1 = FileUtil.readBigFile(path, readFileBean1, datas -> {
if (readFileBean1.getStartRowNum() == 1) {
datas.remove(0);//跳过第一行
}
return datas.stream().map(str -> {
//自定义处理每一条数据
String[] split = str.split(",");
AppnodeCertCsvBean app = new AppnodeCertCsvBean();
app.setEnable(getValue(split, 0));
app.setDomain(getValue(split, 1));
app.setProtocol(getValue(split, 2));
app.setDeployHost(getValue(split, 3));
app.setDeployPath(getValue(split, 4));
app.setUname(getValue(split, 5));
app.setPwd(getValue(split, 6));
if (StrUtil.isNotEmpty(getValue(split, 7))) {
app.setAppnodeId(Integer.valueOf(getValue(split, 7)));
}
return app;
}).collect(Collectors.toList());
});
System.out.println("自定义每行数据的处理============================================");
System.out.println(JsonUtil.formatPrinter(bean1));
System.out.println("自定义每行数据的处理============================================");
//直接使用提供的csv文件读取
ReadFileBean<AppnodeCertCsvBean> readFileBean = new ReadFileBean<>(2);
do {
ReadFileBean<AppnodeCertCsvBean> bean = FileUtil.readBigFile(path, readFileBean, AppnodeCertCsvBean.class);
System.out.println("直接使用提供的csv文件读取============================================");
System.out.println(JsonUtil.formatPrinter(bean));
System.out.println("直接使用提供的csv文件读取============================================");
} while (readFileBean.hasNext());
}
private static String getValue(String[] value, int index) {
try {
return value[index];
} catch (Exception e) {
return "";
}
}
}

View File

@@ -1,5 +1,7 @@
package com.yexuejc.base.util;
import com.yexuejc.base.annotation.ToUeProperty;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;

View File

@@ -0,0 +1,24 @@
package com.yexuejc.base.util;
import java.util.Arrays;
/**
*
* @author: yexuejc
* @date: 2024/4/8 11:22
*/
public class SysUtilTest {
public static void main(String[] args) {
System.out.println(SysUtil.getCachePath());
System.out.println(SysUtil.getRootPath(SysUtilTest.class, null));
SysUtil.threadRun("test", () -> {
String threadName = Thread.currentThread().getName();
System.out.println("当前线程的名称是:" + threadName);
});
SysUtil.getThreadList().forEach(t -> {
System.out.println("线程名称:" + t.getName());
});
SysUtil.checkJvmMemory();
System.out.println(SysUtil.jvmMemoryIsNotExecutable());
}
}

View File

@@ -0,0 +1,108 @@
package com.yexuejc.base.util.bean;
import java.io.Serializable;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.yexuejc.base.annotation.CsvToBean;
import com.yexuejc.base.converter.IntegerNullValueDeserializer;
/**
*
* @author: yexuejc
* @date: 2024/2/27 10:40
*/
@CsvToBean(header = "enable,domain,protocol,deployHost,deployPath,uname,pwd,appnodeId")
public class AppnodeCertCsvBean implements Serializable {
/**是否生效Y/N*/
private String enable;
/**域名*/
private String domain;
/**
* 部署协议
* appnode
* ssh
* */
private String protocol;
/**
* 部署服务器
* 部署协议appnode: local 本机部署
* 部署协议appnode: 域名 部署的远程appnode域名
* 部署协议ssh : IP
* */
private String deployHost;
/**部署证书位置*/
private String deployPath;
/**服务器账号*/
private String uname;
/**服务器密码*/
private String pwd;
/**
* appnode协议时且远程部署时对应的远程appnode的ApiNodeId
*/
@JsonDeserialize(using = IntegerNullValueDeserializer.class)
private Integer appnodeId;
public String getEnable() {
return enable;
}
public void setEnable(String enable) {
this.enable = enable;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public String getDeployHost() {
return deployHost;
}
public void setDeployHost(String deployHost) {
this.deployHost = deployHost;
}
public String getDeployPath() {
return deployPath;
}
public void setDeployPath(String deployPath) {
this.deployPath = deployPath;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public Integer getAppnodeId() {
return appnodeId;
}
public void setAppnodeId(Integer appnodeId) {
this.appnodeId = appnodeId;
}
}

View File

@@ -0,0 +1,10 @@
是否生效,域名,部署协议,部署服务器,部署证书位置,服务器账号,服务器密码,appnodeId
N,kasm.mx.yexuejc.top,appnode,http://192.168.56.101:8888,,admin,admin,1
N,kasm.mx.yexuejc.top,appnode,local,,,,
N,shop.mx.yexuejc.top,appnode,local,,,,
Y,cloud.yexuejc.top,ssh,118.126.109.109:10371,/home/frpuser/http/cert/,frpuser,yexuejc1,
Y,blog.yexuejc.top,ssh,118.126.109.109:10371,/home/frpuser/http/cert/,frpuser,yexuejc1,
Y,yexuejc.top,ssh,118.126.109.109:10371,/home/frpuser/http/cert/,frpuser,yexuejc1,
Y,jenkins.yexuejc.top,ssh,118.126.109.109:10371,/home/frpuser/http/cert/,frpuser,yexuejc1,
Y,git.yexuejc.top,ssh,118.126.109.109:10371,/home/frpuser/http/cert/,frpuser,yexuejc1,
Y,nexus.yexuejc.top,ssh,118.126.109.109:10371,/home/frpuser/http/cert/,frpuser,yexuejc1,
1 是否生效 域名 部署协议 部署服务器 部署证书位置 服务器账号 服务器密码 appnodeId
2 N kasm.mx.yexuejc.top appnode http://192.168.56.101:8888 admin admin 1
3 N kasm.mx.yexuejc.top appnode local
4 N shop.mx.yexuejc.top appnode local
5 Y cloud.yexuejc.top ssh 118.126.109.109:10371 /home/frpuser/http/cert/ frpuser yexuejc1
6 Y blog.yexuejc.top ssh 118.126.109.109:10371 /home/frpuser/http/cert/ frpuser yexuejc1
7 Y yexuejc.top ssh 118.126.109.109:10371 /home/frpuser/http/cert/ frpuser yexuejc1
8 Y jenkins.yexuejc.top ssh 118.126.109.109:10371 /home/frpuser/http/cert/ frpuser yexuejc1
9 Y git.yexuejc.top ssh 118.126.109.109:10371 /home/frpuser/http/cert/ frpuser yexuejc1
10 Y nexus.yexuejc.top ssh 118.126.109.109:10371 /home/frpuser/http/cert/ frpuser yexuejc1