add utils
This commit is contained in:
parent
6e09a9bd6c
commit
2feb8827fe
13
README.md
13
README.md
|
@ -13,6 +13,17 @@
|
|||
## demo
|
||||
使用参考 [spring-boot-nebula-samples](spring-boot-nebula-samples)模块
|
||||
|
||||
### [spring-boot-nebula-web](spring-boot-nebula-web) 使用
|
||||
|
||||
1. 引入依赖
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>io.github.weihubeats</groupId>
|
||||
<artifactId>spring-boot-nebula-web</artifactId>
|
||||
<version>0.0.01</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
1. 运行[Application.java](spring-boot-nebula-samples%2Fspring-boot-nebula-web-sample%2Fsrc%2Fmain%2Fjava%2Fcom%2Fnebula%2Fweb%2Fsample%2FApplication.java)
|
||||
2. 运行 [http-test-controller.http](spring-boot-nebula-samples%2Fspring-boot-nebula-web-sample%2Fsrc%2Fmain%2Fhttp%2Fhttp-test-controller.http)中的`GET localhost:8088/test`
|
||||
|
||||
|
@ -41,7 +52,7 @@
|
|||
}
|
||||
```
|
||||
|
||||
### 提供开箱即用的分页对象
|
||||
#### 提供开箱即用的分页对象
|
||||
- [NebulaPage.java](spring-boot-nebula-web%2Fsrc%2Fmain%2Fjava%2Fcom%2Fnebula%2Fweb%2Fboot%2Fapi%2FNebulaPage.java)
|
||||
- [NebulaPageQuery.java](spring-boot-nebula-web%2Fsrc%2Fmain%2Fjava%2Fcom%2Fnebula%2Fweb%2Fboot%2Fapi%2FNebulaPageQuery.java)
|
||||
|
||||
|
|
6
pom.xml
6
pom.xml
|
@ -25,6 +25,8 @@
|
|||
<revision>0.0.01</revision>
|
||||
<flatten-maven-plugin.version>1.2.7</flatten-maven-plugin.version>
|
||||
<maven-gpg-plugin.version>3.0.1</maven-gpg-plugin.version>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
|
||||
|
@ -78,8 +80,8 @@
|
|||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,438 @@
|
|||
package com.nebula.base.utils;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/11/18 13:58
|
||||
* @description:
|
||||
*/
|
||||
public class CharUtil {
|
||||
|
||||
// ---------------------------------------------------------------- simple
|
||||
|
||||
/**
|
||||
* Converts (signed) byte to (unsigned) char.
|
||||
*/
|
||||
public static char toChar(final byte b) {
|
||||
return (char) (b & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts char array into byte array by stripping the high byte of each character.
|
||||
*/
|
||||
public static byte[] toSimpleByteArray(final char[] carr) {
|
||||
final byte[] barr = new byte[carr.length];
|
||||
for (int i = 0; i < carr.length; i++) {
|
||||
barr[i] = (byte) carr[i];
|
||||
}
|
||||
return barr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts char sequence into byte array.
|
||||
*
|
||||
* @see #toSimpleByteArray(char[])
|
||||
*/
|
||||
public static byte[] toSimpleByteArray(final CharSequence charSequence) {
|
||||
final byte[] barr = new byte[charSequence.length()];
|
||||
for (int i = 0; i < barr.length; i++) {
|
||||
barr[i] = (byte) charSequence.charAt(i);
|
||||
}
|
||||
return barr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts byte array to char array by simply extending bytes to chars.
|
||||
*/
|
||||
public static char[] toSimpleCharArray(final byte[] barr) {
|
||||
final char[] carr = new char[barr.length];
|
||||
for (int i = 0; i < barr.length; i++) {
|
||||
carr[i] = (char) (barr[i] & 0xFF);
|
||||
}
|
||||
return carr;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- ascii
|
||||
|
||||
/**
|
||||
* Returns ASCII value of a char. In case of overload, 0x3F is returned.
|
||||
*/
|
||||
public static int toAscii(final char c) {
|
||||
if (c <= 0xFF) {
|
||||
return c;
|
||||
} else {
|
||||
return 0x3F;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts char array into {@link #toAscii(char) ASCII} array.
|
||||
*/
|
||||
public static byte[] toAsciiByteArray(final char[] carr) {
|
||||
final byte[] barr = new byte[carr.length];
|
||||
for (int i = 0; i < carr.length; i++) {
|
||||
barr[i] = (byte) ((int) (carr[i] <= 0xFF ? carr[i] : 0x3F));
|
||||
}
|
||||
return barr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts char sequence into ASCII byte array.
|
||||
*/
|
||||
public static byte[] toAsciiByteArray(final CharSequence charSequence) {
|
||||
final byte[] barr = new byte[charSequence.length()];
|
||||
for (int i = 0; i < barr.length; i++) {
|
||||
final char c = charSequence.charAt(i);
|
||||
barr[i] = (byte) ((int) (c <= 0xFF ? c : 0x3F));
|
||||
}
|
||||
return barr;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- raw arrays
|
||||
|
||||
/**
|
||||
* Converts char array into byte array by replacing each character with two bytes.
|
||||
*/
|
||||
public static byte[] toRawByteArray(final char[] carr) {
|
||||
final byte[] barr = new byte[carr.length << 1];
|
||||
for (int i = 0, bpos = 0; i < carr.length; i++) {
|
||||
final char c = carr[i];
|
||||
barr[bpos++] = (byte) ((c & 0xFF00) >> 8);
|
||||
barr[bpos++] = (byte) (c & 0x00FF);
|
||||
}
|
||||
return barr;
|
||||
}
|
||||
|
||||
public static char[] toRawCharArray(final byte[] barr) {
|
||||
int carrLen = barr.length >> 1;
|
||||
if (carrLen << 1 < barr.length) {
|
||||
carrLen++;
|
||||
}
|
||||
final char[] carr = new char[carrLen];
|
||||
int i = 0, j = 0;
|
||||
while (i < barr.length) {
|
||||
char c = (char) (barr[i] << 8);
|
||||
i++;
|
||||
|
||||
if (i != barr.length) {
|
||||
c += barr[i] & 0xFF;
|
||||
i++;
|
||||
}
|
||||
carr[j++] = c;
|
||||
}
|
||||
return carr;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- encoding
|
||||
|
||||
/**
|
||||
* Converts char array to byte array using default Jodd encoding.
|
||||
*/
|
||||
public static byte[] toByteArray(final char[] carr) {
|
||||
return new String(carr).getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts char array to byte array using provided encoding.
|
||||
*/
|
||||
public static byte[] toByteArray(final char[] carr, final Charset charset) {
|
||||
return new String(carr).getBytes(charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts byte array of default Jodd encoding to char array.
|
||||
*/
|
||||
public static char[] toCharArray(final byte[] barr) {
|
||||
return new String(barr).toCharArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts byte array of specific encoding to char array.
|
||||
*/
|
||||
public static char[] toCharArray(final byte[] barr, final Charset charset) {
|
||||
return new String(barr, charset).toCharArray();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- find
|
||||
|
||||
/**
|
||||
* Match if one character equals to any of the given character.
|
||||
*
|
||||
* @return <code>true</code> if characters match any character from given array,
|
||||
* otherwise <code>false</code>
|
||||
*/
|
||||
public static boolean equalsOne(final char c, final char[] match) {
|
||||
for (final char aMatch : match) {
|
||||
if (c == aMatch) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds index of the first character in given array the matches any from the
|
||||
* given set of characters.
|
||||
*
|
||||
* @return index of matched character or -1
|
||||
*/
|
||||
public static int findFirstEqual(final char[] source, final int index, final char[] match) {
|
||||
for (int i = index; i < source.length; i++) {
|
||||
if (equalsOne(source[i], match)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds index of the first character in given array the matches any from the
|
||||
* given set of characters.
|
||||
*
|
||||
* @return index of matched character or -1
|
||||
*/
|
||||
public static int findFirstEqual(final char[] source, final int index, final char match) {
|
||||
for (int i = index; i < source.length; i++) {
|
||||
if (source[i] == match) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds index of the first character in given array the differs from the
|
||||
* given set of characters.
|
||||
*
|
||||
* @return index of matched character or -1
|
||||
*/
|
||||
public static int findFirstDiff(final char[] source, final int index, final char[] match) {
|
||||
for (int i = index; i < source.length; i++) {
|
||||
if (!equalsOne(source[i], match)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds index of the first character in given array the differs from the
|
||||
* given set of characters.
|
||||
*
|
||||
* @return index of matched character or -1
|
||||
*/
|
||||
public static int findFirstDiff(final char[] source, final int index, final char match) {
|
||||
for (int i = index; i < source.length; i++) {
|
||||
if (source[i] != match) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- is
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if character is a white space ({@code <= ' '}).
|
||||
* White space definition is taken from String class (see: <code>trim()</code>).
|
||||
* This method has different results then <code>Character#isWhitespace</code>."
|
||||
*/
|
||||
public static boolean isWhitespace(final char c) {
|
||||
return c <= ' ';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if specified character is lowercase ASCII.
|
||||
* If user uses only ASCIIs, it is much much faster.
|
||||
*/
|
||||
public static boolean isLowercaseAlpha(final char c) {
|
||||
return (c >= 'a') && (c <= 'z');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if specified character is uppercase ASCII.
|
||||
* If user uses only ASCIIs, it is much much faster.
|
||||
*/
|
||||
public static boolean isUppercaseAlpha(final char c) {
|
||||
return (c >= 'A') && (c <= 'Z');
|
||||
}
|
||||
|
||||
public static boolean isAlphaOrDigit(final char c) {
|
||||
return isDigit(c) || isAlpha(c);
|
||||
}
|
||||
|
||||
public static boolean isWordChar(final char c) {
|
||||
return isDigit(c) || isAlpha(c) || (c == '_');
|
||||
}
|
||||
|
||||
public static boolean isPropertyNameChar(final char c) {
|
||||
return isDigit(c) || isAlpha(c) || (c == '_') || (c == '.') || (c == '[') || (c == ']');
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- RFC
|
||||
|
||||
/**
|
||||
* Indicates whether the given character is in the {@code ALPHA} set.
|
||||
*
|
||||
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
|
||||
*/
|
||||
public static boolean isAlpha(final char c) {
|
||||
return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the given character is in the {@code DIGIT} set.
|
||||
*
|
||||
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
|
||||
*/
|
||||
public static boolean isDigit(final char c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the given character is the hexadecimal digit.
|
||||
*/
|
||||
public static boolean isHexDigit(final char c) {
|
||||
return (c >= '0' && c <= '9') || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the given character is in the <i>gen-delims</i> set.
|
||||
*
|
||||
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
|
||||
*/
|
||||
public static boolean isGenericDelimiter(final int c) {
|
||||
switch (c) {
|
||||
case ':':
|
||||
case '/':
|
||||
case '?':
|
||||
case '#':
|
||||
case '[':
|
||||
case ']':
|
||||
case '@':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the given character is in the <i>sub-delims</i> set.
|
||||
*
|
||||
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
|
||||
*/
|
||||
public static boolean isSubDelimiter(final int c) {
|
||||
switch (c) {
|
||||
case '!':
|
||||
case '$':
|
||||
case '&':
|
||||
case '\'':
|
||||
case '(':
|
||||
case ')':
|
||||
case '*':
|
||||
case '+':
|
||||
case ',':
|
||||
case ';':
|
||||
case '=':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the given character is in the <i>reserved</i> set.
|
||||
*
|
||||
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
|
||||
*/
|
||||
public static boolean isReserved(final char c) {
|
||||
return isGenericDelimiter(c) || isSubDelimiter(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the given character is in the <i>unreserved</i> set.
|
||||
*
|
||||
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
|
||||
*/
|
||||
public static boolean isUnreserved(final char c) {
|
||||
return isAlpha(c) || isDigit(c) || c == '-' || c == '.' || c == '_' || c == '~';
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the given character is in the <i>pchar</i> set.
|
||||
*
|
||||
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
|
||||
*/
|
||||
public static boolean isPchar(final char c) {
|
||||
return isUnreserved(c) || isSubDelimiter(c) || c == ':' || c == '@';
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- conversions
|
||||
|
||||
/**
|
||||
* Uppers lowercase ASCII char.
|
||||
*/
|
||||
public static char toUpperAscii(char c) {
|
||||
if (isLowercaseAlpha(c)) {
|
||||
c -= (char) 0x20;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lowers uppercase ASCII char.
|
||||
*/
|
||||
public static char toLowerAscii(char c) {
|
||||
if (isUppercaseAlpha(c)) {
|
||||
c += (char) 0x20;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts hex char to int value.
|
||||
*/
|
||||
public static int hex2int(final char c) {
|
||||
switch (c) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return c - '0';
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
return c - 55;
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
return c - 87;
|
||||
default:
|
||||
throw new IllegalArgumentException("Not a hex: " + c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts integer digit to heck char.
|
||||
*/
|
||||
public static char int2hex(final int i) {
|
||||
return HEX_CHARS[i];
|
||||
}
|
||||
|
||||
public static final char[] HEX_CHARS = new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
package com.nebula.base.utils;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/11/18 14:06
|
||||
* @description:
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ClassLoaderStrategy {
|
||||
|
||||
/**
|
||||
* Loads class with given name and optionally provided class loader.
|
||||
*/
|
||||
Class loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException;
|
||||
|
||||
/**
|
||||
* Default Jodd class loader strategy.
|
||||
* Loads a class with a given name dynamically, more reliable then <code>Class.forName</code>.
|
||||
* <p>
|
||||
* Class will be loaded using class loaders in the following order:
|
||||
* <ul>
|
||||
* <li>provided class loader (if any)</li>
|
||||
* <li><code>Thread.currentThread().getContextClassLoader()}</code></li>
|
||||
* <li>caller classloader</li>
|
||||
* </ul>
|
||||
*/
|
||||
class DefaultClassLoaderStrategy implements ClassLoaderStrategy {
|
||||
|
||||
/**
|
||||
* List of primitive type names.
|
||||
*/
|
||||
public static final String[] PRIMITIVE_TYPE_NAMES = new String[] {
|
||||
"boolean", "byte", "char", "double", "float", "int", "long", "short",
|
||||
};
|
||||
/**
|
||||
* List of primitive types that matches names list.
|
||||
*/
|
||||
public static final Class[] PRIMITIVE_TYPES = new Class[] {
|
||||
boolean.class, byte.class, char.class, double.class, float.class, int.class, long.class, short.class,
|
||||
};
|
||||
/**
|
||||
* List of primitive bytecode characters that matches names list.
|
||||
*/
|
||||
public static final char[] PRIMITIVE_BYTECODE_NAME = new char[] {
|
||||
'Z', 'B', 'C', 'D', 'F', 'I', 'J', 'S'
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------- flags
|
||||
|
||||
protected boolean loadArrayClassByComponentTypes = false;
|
||||
|
||||
/**
|
||||
* Returns arrays class loading strategy.
|
||||
*/
|
||||
public boolean isLoadArrayClassByComponentTypes() {
|
||||
return loadArrayClassByComponentTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines arrays class loading strategy.
|
||||
* If <code>false</code> (default), classes will be loaded by <code>Class.forName</code>.
|
||||
* If <code>true</code>, classes will be loaded by reflection and component types.
|
||||
*/
|
||||
public void setLoadArrayClassByComponentTypes(final boolean loadArrayClassByComponentTypes) {
|
||||
this.loadArrayClassByComponentTypes = loadArrayClassByComponentTypes;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- names
|
||||
|
||||
/**
|
||||
* Prepares classname for loading, respecting the arrays.
|
||||
* Returns <code>null</code> if class name is not an array.
|
||||
*/
|
||||
public static String prepareArrayClassnameForLoading(String className) {
|
||||
final int bracketCount = StringUtils.count(className, '[');
|
||||
|
||||
if (bracketCount == 0) {
|
||||
// not an array
|
||||
return null;
|
||||
}
|
||||
|
||||
final String brackets = StringUtils.repeat('[', bracketCount);
|
||||
|
||||
final int bracketIndex = className.indexOf('[');
|
||||
className = className.substring(0, bracketIndex);
|
||||
|
||||
final int primitiveNdx = getPrimitiveClassNameIndex(className);
|
||||
if (primitiveNdx >= 0) {
|
||||
className = String.valueOf(PRIMITIVE_BYTECODE_NAME[primitiveNdx]);
|
||||
|
||||
return brackets + className;
|
||||
} else {
|
||||
return brackets + 'L' + className + ';';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects if provided class name is a primitive type.
|
||||
* Returns >= 0 number if so.
|
||||
*/
|
||||
private static int getPrimitiveClassNameIndex(final String className) {
|
||||
final int dotIndex = className.indexOf('.');
|
||||
if (dotIndex != -1) {
|
||||
return -1;
|
||||
}
|
||||
return Arrays.binarySearch(PRIMITIVE_TYPE_NAMES, className);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- load
|
||||
|
||||
/**
|
||||
* Loads class by name.
|
||||
*/
|
||||
@Override
|
||||
public Class loadClass(final String className, final ClassLoader classLoader) throws ClassNotFoundException {
|
||||
final String arrayClassName = prepareArrayClassnameForLoading(className);
|
||||
|
||||
if ((className.indexOf('.') == -1) && (arrayClassName == null)) {
|
||||
// maybe a primitive
|
||||
final int primitiveNdx = getPrimitiveClassNameIndex(className);
|
||||
if (primitiveNdx >= 0) {
|
||||
return PRIMITIVE_TYPES[primitiveNdx];
|
||||
}
|
||||
}
|
||||
|
||||
// try #1 - using provided class loader
|
||||
if (classLoader != null) {
|
||||
final Class klass = loadClass(className, arrayClassName, classLoader);
|
||||
|
||||
if (klass != null) {
|
||||
return klass;
|
||||
}
|
||||
}
|
||||
|
||||
// try #2 - using thread class loader
|
||||
final ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
|
||||
if ((currentThreadClassLoader != null) && (currentThreadClassLoader != classLoader)) {
|
||||
final Class klass = loadClass(className, arrayClassName, currentThreadClassLoader);
|
||||
|
||||
if (klass != null) {
|
||||
return klass;
|
||||
}
|
||||
}
|
||||
|
||||
// try #3 - using caller classloader, similar as Class.forName()
|
||||
//Class callerClass = ReflectUtil.getCallerClass(2);
|
||||
final Class callerClass = ClassUtil.getCallerClass();
|
||||
final ClassLoader callerClassLoader = callerClass.getClassLoader();
|
||||
|
||||
if ((callerClassLoader != classLoader) && (callerClassLoader != currentThreadClassLoader)) {
|
||||
final Class klass = loadClass(className, arrayClassName, callerClassLoader);
|
||||
|
||||
if (klass != null) {
|
||||
return klass;
|
||||
}
|
||||
}
|
||||
|
||||
// try #4 - everything failed, try alternative array loader
|
||||
if (arrayClassName != null) {
|
||||
try {
|
||||
return loadArrayClassByComponentType(className, classLoader);
|
||||
} catch (final ClassNotFoundException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassNotFoundException("Class not found: " + className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a class using provided class loader.
|
||||
* If class is an array, it will be first loaded using the <code>Class.forName</code>!
|
||||
* We must use this since for JDK {@literal >=} 6 arrays will be not loaded using classloader,
|
||||
* but only with <code>forName</code> method. However, array loading strategy can be
|
||||
* {@link #setLoadArrayClassByComponentTypes(boolean) changed}.
|
||||
*/
|
||||
protected Class loadClass(final String className, final String arrayClassName, final ClassLoader classLoader) {
|
||||
if (arrayClassName != null) {
|
||||
try {
|
||||
if (loadArrayClassByComponentTypes) {
|
||||
return loadArrayClassByComponentType(className, classLoader);
|
||||
} else {
|
||||
return Class.forName(arrayClassName, true, classLoader);
|
||||
}
|
||||
} catch (final ClassNotFoundException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return classLoader.loadClass(className);
|
||||
} catch (final ClassNotFoundException ignore) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads array class using component type.
|
||||
*/
|
||||
protected Class loadArrayClassByComponentType(final String className,
|
||||
final ClassLoader classLoader) throws ClassNotFoundException {
|
||||
final int ndx = className.indexOf('[');
|
||||
final int multi = StringUtils.count(className, '[');
|
||||
|
||||
final String componentTypeName = className.substring(0, ndx);
|
||||
|
||||
final Class componentType = loadClass(componentTypeName, classLoader);
|
||||
|
||||
if (multi == 1) {
|
||||
return Array.newInstance(componentType, 0).getClass();
|
||||
}
|
||||
|
||||
final int[] multiSizes;
|
||||
|
||||
if (multi == 2) {
|
||||
multiSizes = new int[] {0, 0};
|
||||
} else if (multi == 3) {
|
||||
multiSizes = new int[] {0, 0, 0};
|
||||
} else {
|
||||
multiSizes = (int[]) Array.newInstance(int.class, multi);
|
||||
}
|
||||
|
||||
return Array.newInstance(componentType, multiSizes).getClass();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
package com.nebula.base.utils;
|
||||
|
||||
import com.nebula.base.utils.io.IOUtil;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/11/18 13:57
|
||||
* @description:
|
||||
*/
|
||||
public class ClassLoaderUtil {
|
||||
|
||||
public static ClassLoaderStrategy classLoaderStrategy = new ClassLoaderStrategy.DefaultClassLoaderStrategy();
|
||||
|
||||
// ---------------------------------------------------------------- default class loader
|
||||
|
||||
/**
|
||||
* Returns default class loader. By default, it is {@link #getContextClassLoader() threads context class loader}.
|
||||
* If this one is <code>null</code>, then class loader of the <b>caller class</b> is returned.
|
||||
*/
|
||||
public static ClassLoader getDefaultClassLoader() {
|
||||
ClassLoader cl = getContextClassLoader();
|
||||
if (cl == null) {
|
||||
final Class callerClass = ClassUtil.getCallerClass(2);
|
||||
cl = callerClass.getClassLoader();
|
||||
}
|
||||
return cl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns thread context class loader.
|
||||
*/
|
||||
public static ClassLoader getContextClassLoader() {
|
||||
if (System.getSecurityManager() == null) {
|
||||
return Thread.currentThread().getContextClassLoader();
|
||||
} else {
|
||||
return AccessController.doPrivileged(
|
||||
(PrivilegedAction<ClassLoader>) () -> Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns system class loader.
|
||||
*/
|
||||
public static ClassLoader getSystemClassLoader() {
|
||||
if (System.getSecurityManager() == null) {
|
||||
return ClassLoader.getSystemClassLoader();
|
||||
} else {
|
||||
return AccessController.doPrivileged(
|
||||
(PrivilegedAction<ClassLoader>) ClassLoader::getSystemClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- classpath
|
||||
|
||||
private static final String[] MANIFESTS = {"Manifest.mf", "manifest.mf", "MANIFEST.MF"};
|
||||
|
||||
/**
|
||||
* Returns classpath item manifest or <code>null</code> if not found.
|
||||
*/
|
||||
public static Manifest getClasspathItemManifest(final File classpathItem) {
|
||||
Manifest manifest = null;
|
||||
|
||||
if (classpathItem.isFile()) {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(classpathItem);
|
||||
final JarFile jar = new JarFile(classpathItem);
|
||||
manifest = jar.getManifest();
|
||||
} catch (final IOException ignore) {
|
||||
} finally {
|
||||
IOUtil.close(fis);
|
||||
}
|
||||
} else {
|
||||
final File metaDir = new File(classpathItem, "META-INF");
|
||||
File manifestFile = null;
|
||||
if (metaDir.isDirectory()) {
|
||||
for (final String m : MANIFESTS) {
|
||||
final File mFile = new File(metaDir, m);
|
||||
if (mFile.isFile()) {
|
||||
manifestFile = mFile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (manifestFile != null) {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(manifestFile);
|
||||
manifest = new Manifest(fis);
|
||||
} catch (final IOException ignore) {
|
||||
} finally {
|
||||
IOUtil.close(fis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return manifest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns base folder for classpath item. If item is a (jar) file,
|
||||
* its parent is returned. If item is a directory, its name is returned.
|
||||
*/
|
||||
public static String getClasspathItemBaseDir(final File classpathItem) {
|
||||
final String base;
|
||||
if (classpathItem.isFile()) {
|
||||
base = classpathItem.getParent();
|
||||
} else {
|
||||
base = classpathItem.toString();
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- class stream
|
||||
|
||||
/**
|
||||
* Opens a class of the specified name for reading using class classloader.
|
||||
*/
|
||||
public static InputStream getClassAsStream(final Class clazz) throws IOException {
|
||||
return ResourcesUtil.getResourceAsStream(ClassUtil.convertClassNameToFileName(clazz), clazz.getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a class of the specified name for reading. No specific classloader is used
|
||||
* for loading class.
|
||||
*/
|
||||
public static InputStream getClassAsStream(final String className) throws IOException {
|
||||
return ResourcesUtil.getResourceAsStream(ClassUtil.convertClassNameToFileName(className));
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a class of the specified name for reading using provided class loader.
|
||||
*/
|
||||
public static InputStream getClassAsStream(final String className,
|
||||
final ClassLoader classLoader) throws IOException {
|
||||
return ResourcesUtil.getResourceAsStream(ClassUtil.convertClassNameToFileName(className), classLoader);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- load class
|
||||
|
||||
/**
|
||||
* Loads a class using default class loader strategy.
|
||||
*
|
||||
* @see ClassLoaderStrategy.DefaultClassLoaderStrategy
|
||||
*/
|
||||
public static Class loadClass(final String className) throws ClassNotFoundException {
|
||||
return classLoaderStrategy.loadClass(className, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a class using default class loader strategy.
|
||||
*
|
||||
* @see ClassLoaderStrategy.DefaultClassLoaderStrategy
|
||||
*/
|
||||
public static Class loadClass(final String className, final ClassLoader classLoader) throws ClassNotFoundException {
|
||||
return classLoaderStrategy.loadClass(className, classLoader);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- class location
|
||||
|
||||
/**
|
||||
* Returns location of the class. If class is not in a jar, it's classpath
|
||||
* is returned; otherwise the jar location.
|
||||
*/
|
||||
public static String classLocation(final Class clazz) {
|
||||
return clazz.getProtectionDomain().getCodeSource().getLocation().getPath();
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -28,11 +28,11 @@ public class DataUtils {
|
|||
return true;
|
||||
}
|
||||
if (pObj instanceof String) {
|
||||
return ((String) pObj).trim().length() == 0;
|
||||
return ((String) pObj).trim().isEmpty();
|
||||
} else if (pObj instanceof Collection<?>) {
|
||||
return ((Collection<?>) pObj).size() == 0;
|
||||
return ((Collection<?>) pObj).isEmpty();
|
||||
} else if (pObj instanceof Map<?, ?>) {
|
||||
return ((Map<?, ?>) pObj).size() == 0;
|
||||
return ((Map<?, ?>) pObj).isEmpty();
|
||||
} else if (pObj instanceof Object[]) {
|
||||
return ((Object[]) pObj).length == 0;
|
||||
} else if (pObj instanceof boolean[]) {
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
package com.nebula.base.utils;
|
||||
|
||||
import com.nebula.base.utils.io.IOUtil;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/11/18 14:05
|
||||
* @description:
|
||||
*/
|
||||
public interface DigestEngine {
|
||||
|
||||
class JavaDigestEngine implements DigestEngine {
|
||||
|
||||
private final MessageDigest messageDigest;
|
||||
|
||||
JavaDigestEngine(final String algorithm) {
|
||||
try {
|
||||
this.messageDigest = MessageDigest.getInstance(algorithm);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] digest(final byte[] byteArray) {
|
||||
messageDigest.update(byteArray);
|
||||
return messageDigest.digest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] digest(final File file) throws IOException {
|
||||
FileInputStream fis = null;
|
||||
BufferedInputStream bis = null;
|
||||
DigestInputStream dis = null;
|
||||
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
bis = new BufferedInputStream(fis);
|
||||
dis = new DigestInputStream(bis, messageDigest);
|
||||
|
||||
while (dis.read() != -1) {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
IOUtil.close(dis);
|
||||
IOUtil.close(bis);
|
||||
IOUtil.close(fis);
|
||||
}
|
||||
|
||||
return messageDigest.digest();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new MD2 digest.
|
||||
*/
|
||||
public static DigestEngine md2() {
|
||||
return new JavaDigestEngine("MD2");
|
||||
}
|
||||
/**
|
||||
* Creates new MD5 digest.
|
||||
*/
|
||||
public static DigestEngine md5() {
|
||||
return new JavaDigestEngine("MD5");
|
||||
}
|
||||
/**
|
||||
* Creates new SHA-1 digest.
|
||||
*/
|
||||
public static DigestEngine sha1() {
|
||||
return new JavaDigestEngine("SHA-1");
|
||||
}
|
||||
/**
|
||||
* Creates new SHA-256 digest.
|
||||
*/
|
||||
public static DigestEngine sha256() {
|
||||
return new JavaDigestEngine("SHA-256");
|
||||
}
|
||||
/**
|
||||
* Creates new SHA-384 digest.
|
||||
*/
|
||||
public static DigestEngine sha384() {
|
||||
return new JavaDigestEngine("SHA-384");
|
||||
}
|
||||
/**
|
||||
* Creates new SHA-512 digest.
|
||||
*/
|
||||
public static DigestEngine sha512() {
|
||||
return new JavaDigestEngine("SHA-512");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns byte-hash of input byte array.
|
||||
*/
|
||||
public byte[] digest(byte[] input);
|
||||
|
||||
/**
|
||||
* Returns byte-hash of input string.
|
||||
*/
|
||||
public default byte[] digest(final String input) {
|
||||
return digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns digest of a file. Implementations may not read the whole
|
||||
* file into the memory.
|
||||
*/
|
||||
public byte[] digest(final File file) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns string hash of input byte array.
|
||||
*/
|
||||
public default String digestString(final byte[] byteArray) {
|
||||
return StringUtils.toHexString(digest(byteArray));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns string hash of input string.
|
||||
*/
|
||||
public default String digestString(final String input) {
|
||||
return StringUtils.toHexString(digest(input));
|
||||
}
|
||||
|
||||
public default String digestString(final File file) throws IOException {
|
||||
return StringUtils.toHexString(digest(file));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package com.nebula.base.utils;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/11/18 13:59
|
||||
* @description:
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@ToString
|
||||
public enum PatternEnum {
|
||||
|
||||
/**
|
||||
* 英文字母 、数字和下划线
|
||||
*/
|
||||
GENERAL(Pattern.compile("^\\w+$")),
|
||||
|
||||
/**
|
||||
* 数字
|
||||
*/
|
||||
NUMBERS(Pattern.compile("\\d+")),
|
||||
|
||||
/**
|
||||
* 小写字母
|
||||
*/
|
||||
LOWER_CASE(Pattern.compile("[a-z]+")),
|
||||
|
||||
/**
|
||||
* 小写字母
|
||||
*/
|
||||
UPPER_CASE(Pattern.compile("[A-Z]+")),
|
||||
|
||||
/**
|
||||
* 英文字母
|
||||
*/
|
||||
WORD(Pattern.compile("[a-zA-Z]+")),
|
||||
|
||||
/**
|
||||
* 单个汉字
|
||||
*/
|
||||
CHINESE(Pattern.compile("[\u4E00-\u9FFF]")),
|
||||
|
||||
/**
|
||||
* 汉字
|
||||
*/
|
||||
CHINESE_WORD(Pattern.compile("[\u4E00-\u9FFF]+")),
|
||||
|
||||
/**
|
||||
* 电话
|
||||
*/
|
||||
MOBILE(Pattern.compile("(?:0|86|\\+86)?1[3456789]\\d{9}")),
|
||||
|
||||
/**
|
||||
* 身份证18位
|
||||
*/
|
||||
CITIZEN_ID(Pattern.compile("[1-9]\\d{5}[1-2]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}(\\d|X|x)")),
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
MAIL(Pattern.compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*")),
|
||||
|
||||
/**
|
||||
* emoji表情
|
||||
*/
|
||||
EMOJI(Pattern.compile("[\\x{10000}-\\x{10ffff}\ud800-\udfff]")),
|
||||
|
||||
/**
|
||||
* emoji表情编码格式
|
||||
*/
|
||||
EMOJI_DECODE(Pattern.compile("\\[\\[EMOJI:(.*?)\\]\\]")),
|
||||
|
||||
/**
|
||||
* 正则分组符号格式
|
||||
*/
|
||||
GROUP_VAR(Pattern.compile("\\$(\\d+)")),
|
||||
|
||||
/**
|
||||
* 特殊符号(~!@#$%^&*()_+|<>,.?/:;'[]{}\)
|
||||
*/
|
||||
SPEC_SYMBOL(Pattern.compile("[~!@#$%^&*()_+|<>,.?/:;'\\[\\]{}\"]+"));
|
||||
|
||||
/**
|
||||
* 正则表达式
|
||||
*/
|
||||
private Pattern pattern;
|
||||
|
||||
public boolean isMatch(String input) {
|
||||
return pattern.matcher(input).matches();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
package com.nebula.base.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/11/18 13:59
|
||||
* @description:
|
||||
*/
|
||||
public class RegexUtils {
|
||||
|
||||
/**
|
||||
* 给定内容是否匹配正则表达式
|
||||
*
|
||||
* @param regex 正则表达式
|
||||
* @param content 内容
|
||||
* @return 正则为null或者""则不检查,返回true,内容为null返回false
|
||||
*/
|
||||
public static boolean isMatch(String regex, String content) {
|
||||
return DataUtils.isEmpty(regex) || !DataUtils.isEmpty(content) && isMatch(Pattern.compile(regex), content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 给定内容是否匹配正则
|
||||
*
|
||||
* @param pattern 编译后的正则模式
|
||||
* @param content 内容
|
||||
* @return 正则为null或者""则不检查,返回true,内容为null返回false
|
||||
*/
|
||||
public static boolean isMatch(Pattern pattern, String content) {
|
||||
return DataUtils.isEmpty(pattern) || !DataUtils.isEmpty(content) && pattern.matcher(content).matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除匹配正则表达式的全部内容
|
||||
*
|
||||
* @param regex 正则表达式
|
||||
* @param content 内容
|
||||
* @return 删除后剩余的内容,如果正则为空或""则不检查返回输入的内容
|
||||
*/
|
||||
public static String deleteAll(String regex, String content) {
|
||||
if (DataUtils.isEmpty(regex)) {
|
||||
return content;
|
||||
}
|
||||
return deleteAll(Pattern.compile(regex), content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除匹配正则表达式的全部内容
|
||||
*
|
||||
* @param pattern 编译后的正则模式
|
||||
* @param content 内容
|
||||
* @return 删除后剩余的内容,如果正则为空或""则不检查返回输入的内容
|
||||
*/
|
||||
public static String deleteAll(Pattern pattern, String content) {
|
||||
if (DataUtils.isEmpty(pattern)) {
|
||||
return content;
|
||||
}
|
||||
return pattern.matcher(content).replaceAll(StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得内容中匹配的所有结果
|
||||
*
|
||||
* @param regex 正则表达式
|
||||
* @param content 被查找的内容
|
||||
* @return 结果List列表
|
||||
*/
|
||||
public static List<String> findAll(String regex, String content) {
|
||||
return findAll(regex, content, new ArrayList<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得内容中匹配的所有结果
|
||||
*
|
||||
* @param pattern 编译后的正则模式
|
||||
* @param content 被查找的内容
|
||||
* @return 结果List列表
|
||||
*/
|
||||
public static List<String> findAll(Pattern pattern, String content) {
|
||||
return findAll(pattern, content, new ArrayList<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得内容中匹配的所有结果
|
||||
*
|
||||
* @param <T> 集合类型
|
||||
* @param regex 正则表达式
|
||||
* @param content 被查找的内容
|
||||
* @param collection 返回的集合类型
|
||||
* @return 结果集
|
||||
*/
|
||||
public static <T extends Collection<String>> T findAll(String regex, String content, T collection) {
|
||||
if (DataUtils.isEmpty(regex)) {
|
||||
return null;
|
||||
}
|
||||
return findAll(Pattern.compile(regex), content, 0, collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得内容中匹配的所有结果
|
||||
*
|
||||
* @param <T> 集合类型
|
||||
* @param pattern 编译后的正则模式
|
||||
* @param content 被查找的内容
|
||||
* @param collection 返回的集合类型
|
||||
* @return 结果集
|
||||
*/
|
||||
public static <T extends Collection<String>> T findAll(Pattern pattern, String content, T collection) {
|
||||
return findAll(pattern, content, 0, collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得内容中匹配的所有结果
|
||||
*
|
||||
* @param <T> 集合类型
|
||||
* @param regex 正则表达式
|
||||
* @param content 被查找的内容
|
||||
* @param group 正则的分组
|
||||
* @param collection 返回的集合类型
|
||||
* @return 结果集
|
||||
*/
|
||||
public static <T extends Collection<String>> T findAll(String regex, String content, int group, T collection) {
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
return findAll(pattern, content, group, collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得内容中匹配的所有结果
|
||||
*
|
||||
* @param pattern 编译后的正则模式
|
||||
* @param content 被查找的内容
|
||||
* @param group 正则的分组
|
||||
* @param collection 返回的集合类型
|
||||
* @param <T> 集合类型
|
||||
* @return 结果集
|
||||
*/
|
||||
public static <T extends Collection<String>> T findAll(Pattern pattern, String content, int group, T collection) {
|
||||
if (DataUtils.isEmpty(pattern) || DataUtils.isEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
if (null == collection) {
|
||||
throw new NullPointerException("Null collection param provided!");
|
||||
}
|
||||
Matcher matcher = pattern.matcher(content);
|
||||
while (matcher.find()) {
|
||||
collection.add(matcher.group(group));
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换内容中匹配的所有结果
|
||||
*
|
||||
* @param regex 正则表达式
|
||||
* @param content 被替换的内容
|
||||
* @param replacementTemplate 替换的文本模板,可以使用$1、$2、$3等变量提取正则匹配出的内容
|
||||
* @return 返回替换后结果
|
||||
*/
|
||||
public static String replaceAll(String regex, String content, String replacementTemplate) {
|
||||
return replaceAll(content, Pattern.compile(regex), replacementTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换内容中匹配的所有结果
|
||||
*
|
||||
* @param content 被替换的内容
|
||||
* @param pattern 编译后的正则模式
|
||||
* @param replacementTemplate 替换的文本模板,可以使用$1、$2、$3等变量提取正则匹配出的内容
|
||||
* @return 返回替换后结果
|
||||
*/
|
||||
public static String replaceAll(String content, Pattern pattern, String replacementTemplate) {
|
||||
if (DataUtils.isEmpty(content)) {
|
||||
return content;
|
||||
}
|
||||
final Matcher matcher = pattern.matcher(content);
|
||||
if (DataUtils.isEmpty(matcher)) {
|
||||
return content;
|
||||
}
|
||||
final Set<String> varNums = findAll(PatternEnum.GROUP_VAR.getPattern(), replacementTemplate, 1, new HashSet<String>());
|
||||
if (DataUtils.isEmpty(varNums)) {
|
||||
return content;
|
||||
}
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
String replacement = replacementTemplate;
|
||||
for (String var : varNums) {
|
||||
int group = Integer.parseInt(var);
|
||||
replacement = replacement.replace("$" + var, matcher.group(group));
|
||||
}
|
||||
matcher.appendReplacement(sb, (replacement));
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换内容中匹配的所有结果
|
||||
*
|
||||
* @param content 被替换的内容
|
||||
* @param regex 正则表达式
|
||||
* @param function 处理替换值的方法函数
|
||||
* @param group 正则的分组
|
||||
* @return 返回替换后结果
|
||||
*/
|
||||
public static String replaceAll(String content, String regex, Function<String, String> function, int group) {
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
return replaceAll(content, pattern, function, group);
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换内容中匹配的所有结果
|
||||
*
|
||||
* @param content 被替换的内容
|
||||
* @param pattern 正则
|
||||
* @param function 处理替换值的方法函数
|
||||
* @param group 正则的分组
|
||||
* @return 返回替换后结果
|
||||
*/
|
||||
public static String replaceAll(String content, Pattern pattern, Function<String, String> function, int group) {
|
||||
Matcher matcher = pattern.matcher(content);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
try {
|
||||
String replace = function.apply(matcher.group(group));
|
||||
matcher.appendReplacement(sb, replace);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换内容中匹配的所有结果
|
||||
*
|
||||
* @param content 被替换的内容
|
||||
* @param pattern 正则
|
||||
* @param function 处理替换值的方法函数
|
||||
* @return 返回替换后结果
|
||||
*/
|
||||
public static String replaceAll(String content, Pattern pattern, Function<String, String> function) {
|
||||
return replaceAll(content, pattern, function, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将星号字符转为可正则匹配的字段, * 表示任何长度的[0-9][a-z][A-Z]
|
||||
*
|
||||
* 暂时不考虑 星不连续问题
|
||||
* **aaa √
|
||||
* aaa** √
|
||||
* a**a √
|
||||
* *aa* ×
|
||||
*
|
||||
* @param str 匹配原始字段
|
||||
* @return 符合正则规则的字段
|
||||
*/
|
||||
public static String asteriskMatching(String str) {
|
||||
|
||||
var firstIndex = str.indexOf("*");
|
||||
var lastIndexOf = str.lastIndexOf("*");
|
||||
var length = str.length() - 1;
|
||||
|
||||
int fuzzyLength = lastIndexOf - firstIndex + 1;
|
||||
//todo 后续再重构兼容星不连续类型字段
|
||||
if (fuzzyLength == length + 1) {
|
||||
throw new RuntimeException("暂时不兼容该类型字段");
|
||||
}
|
||||
|
||||
String fuzzyPattern = "(\\\\w)*";
|
||||
var patterStr = str.replaceAll("\\*".repeat(Math.max(0, fuzzyLength)), fuzzyPattern);
|
||||
return "^" + patterStr + "$";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
package com.nebula.base.utils;
|
||||
|
||||
import com.nebula.base.utils.io.IOUtil;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/11/18 14:01
|
||||
* @description:
|
||||
*/
|
||||
public class ResourcesUtil {
|
||||
|
||||
// ---------------------------------------------------------------- get resource
|
||||
|
||||
/**
|
||||
* Retrieves given resource as URL.
|
||||
* @see #getResourceUrl(String, ClassLoader)
|
||||
*/
|
||||
public static URL getResourceUrl(final String resourceName) {
|
||||
return getResourceUrl(resourceName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves given resource as URL. Resource is always absolute and may
|
||||
* starts with a slash character.
|
||||
* <p>
|
||||
* Resource will be loaded using class loaders in the following order:
|
||||
* <ul>
|
||||
* <li>{@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}</li>
|
||||
* <li>{@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}</li>
|
||||
* <li>if <code>callingClass</code> is provided: {@link Class#getClassLoader() callingClass.getClassLoader()}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static URL getResourceUrl(String resourceName, final ClassLoader classLoader) {
|
||||
|
||||
if (resourceName.startsWith("/")) {
|
||||
resourceName = resourceName.substring(1);
|
||||
}
|
||||
|
||||
URL resourceUrl;
|
||||
|
||||
// try #1 - using provided class loader
|
||||
if (classLoader != null) {
|
||||
resourceUrl = classLoader.getResource(resourceName);
|
||||
if (resourceUrl != null) {
|
||||
return resourceUrl;
|
||||
}
|
||||
}
|
||||
|
||||
// try #2 - using thread class loader
|
||||
final ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
if ((currentThreadClassLoader != null) && (currentThreadClassLoader != classLoader)) {
|
||||
resourceUrl = currentThreadClassLoader.getResource(resourceName);
|
||||
if (resourceUrl != null) {
|
||||
return resourceUrl;
|
||||
}
|
||||
}
|
||||
|
||||
// try #3 - using caller classloader, similar as Class.forName()
|
||||
final Class callerClass = ClassUtil.getCallerClass(2);
|
||||
final ClassLoader callerClassLoader = callerClass.getClassLoader();
|
||||
|
||||
if ((callerClassLoader != classLoader) && (callerClassLoader != currentThreadClassLoader)) {
|
||||
resourceUrl = callerClassLoader.getResource(resourceName);
|
||||
if (resourceUrl != null) {
|
||||
return resourceUrl;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- get resource string
|
||||
|
||||
public static String getResourceAsString(final String resourceName) throws IOException {
|
||||
final InputStream inputStream = getResourceAsStream(resourceName);
|
||||
try {
|
||||
final char[] data = IOUtil.readChars(inputStream);
|
||||
return new String(data);
|
||||
}
|
||||
finally {
|
||||
IOUtil.close(inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- get resource stream
|
||||
|
||||
/**
|
||||
* Opens a resource of the specified name for reading.
|
||||
* @see #getResourceAsStream(String, ClassLoader)
|
||||
*/
|
||||
public static InputStream getResourceAsStream(final String resourceName) throws IOException {
|
||||
return getResourceAsStream(resourceName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a resource of the specified name for reading.
|
||||
* @see #getResourceUrl(String, ClassLoader)
|
||||
*/
|
||||
public static InputStream getResourceAsStream(final String resourceName, final ClassLoader callingClass) throws IOException {
|
||||
final URL url = getResourceUrl(resourceName, callingClass);
|
||||
if (url != null) {
|
||||
return url.openStream();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a resource of the specified name for reading. Controls caching,
|
||||
* that is important when the same jar is reloaded using custom classloader.
|
||||
*/
|
||||
public static InputStream getResourceAsStream(final String resourceName, final ClassLoader callingClass, final boolean useCache) throws IOException {
|
||||
final URL url = getResourceUrl(resourceName, callingClass);
|
||||
if (url != null) {
|
||||
final URLConnection urlConnection = url.openConnection();
|
||||
urlConnection.setUseCaches(useCache);
|
||||
return urlConnection.getInputStream();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package com.nebula.base.utils;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/11/18 14:02
|
||||
* @description:
|
||||
*/
|
||||
public interface StringPool {
|
||||
|
||||
String AMPERSAND = "&";
|
||||
String AND = "and";
|
||||
String AT = "@";
|
||||
String ASTERISK = "*";
|
||||
String STAR = ASTERISK;
|
||||
String SLASH = "/";
|
||||
char BACK_SLASH = '\\';
|
||||
String DOUBLE_SLASH = "#//";
|
||||
String COLON = ":";
|
||||
String COMMA = ",";
|
||||
String DASH = "-";
|
||||
String DOLLAR = "$";
|
||||
String DOT = ".";
|
||||
String EMPTY = "";
|
||||
String EMPTY_JSON = "{}";
|
||||
String EQUALS = "=";
|
||||
String FALSE = "false";
|
||||
String HASH = "#";
|
||||
String HAT = "^";
|
||||
String LEFT_BRACE = "{";
|
||||
String LEFT_BRACKET = "(";
|
||||
String LEFT_CHEV = "<";
|
||||
String NEWLINE = "\n";
|
||||
String N = "n";
|
||||
String NO = "no";
|
||||
String NULL = "null";
|
||||
String OFF = "off";
|
||||
String ON = "on";
|
||||
String PERCENT = "%";
|
||||
String PIPE = "|";
|
||||
String PLUS = "+";
|
||||
String QUESTION_MARK = "?";
|
||||
String EXCLAMATION_MARK = "!";
|
||||
String QUOTE = "\"";
|
||||
String RETURN = "\r";
|
||||
String TAB = "\t";
|
||||
String RIGHT_BRACE = "}";
|
||||
String RIGHT_BRACKET = ")";
|
||||
String RIGHT_CHEV = ">";
|
||||
String SEMICOLON = ";";
|
||||
String SINGLE_QUOTE = "'";
|
||||
String BACKTICK = "`";
|
||||
String SPACE = " ";
|
||||
String TILDA = "~";
|
||||
String LEFT_SQ_BRACKET = "[";
|
||||
String RIGHT_SQ_BRACKET = "]";
|
||||
String TRUE = "true";
|
||||
String UNDERSCORE = "_";
|
||||
String UTF_8 = "UTF-8";
|
||||
String GBK = "GBK";
|
||||
String ISO_8859_1 = "ISO-8859-1";
|
||||
String Y = "y";
|
||||
String YES = "yes";
|
||||
String ONE = "1";
|
||||
String ZERO = "0";
|
||||
String DOLLAR_LEFT_BRACE = "${";
|
||||
char U_A = 'A';
|
||||
char L_A = 'a';
|
||||
char U_Z = 'Z';
|
||||
char L_Z = 'z';
|
||||
String UNKNOWN = "unknown";
|
||||
String GET = "GET";
|
||||
String POST = "POST";
|
||||
String DOTDOT = "..";
|
||||
|
||||
}
|
|
@ -0,0 +1,871 @@
|
|||
package com.nebula.base.utils;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.slf4j.helpers.FormattingTuple;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/11/18 13:58
|
||||
* @description:
|
||||
*/
|
||||
public class StringUtils {
|
||||
|
||||
public static final String SPACE = " ";
|
||||
public static final String TAB = " ";
|
||||
public static final String DOT = ".";
|
||||
public static final String DOUBLE_DOT = "..";
|
||||
public static final String SLASH = "/";
|
||||
public static final String BACKSLASH = "\\";
|
||||
public static final String EMPTY = "";
|
||||
public static final String CR = "\r";
|
||||
public static final String LF = "\n";
|
||||
public static final String CRLF = "\r\n";
|
||||
public static final String UNDERLINE = "_";
|
||||
public static final String DASHED = "-";
|
||||
public static final String COMMA = ",";
|
||||
public static final String DELIM_START = "{";
|
||||
public static final String DELIM_END = "}";
|
||||
public static final String BRACKET_START = "[";
|
||||
public static final String BRACKET_END = "]";
|
||||
public static final String COLON = ":";
|
||||
|
||||
/**
|
||||
* 将var2参数替换成var1中出现的{}
|
||||
* <pre>
|
||||
* stringFormat("text{}", "a") = texta
|
||||
* stringFormat("text,{},{}", "a", "b") = text,a,b
|
||||
* stringFormat("text{}", Arrays.asList("1", "2", "3")) = text[1, 2, 3]
|
||||
* stringFormat("text\\{}", "a") = text{}
|
||||
* </pre>
|
||||
*
|
||||
* @param var1 字符串
|
||||
* @param var2 参数
|
||||
* @return
|
||||
*/
|
||||
public static String stringFormat(String var1, Object... var2) {
|
||||
return MessageFormatter.arrayFormat(var1, var2).getMessage();
|
||||
}
|
||||
|
||||
public static boolean startsWithIgnoreCase(String str, String prefix) {
|
||||
return str != null && prefix != null && str.length() >= prefix.length() && str.regionMatches(true, 0, prefix, 0, prefix.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断字符串是否为整数
|
||||
*
|
||||
* @param str 字符串
|
||||
* @return
|
||||
*/
|
||||
public static boolean isInteger(String str) {
|
||||
Pattern pattern = Pattern.compile("^[0-9]*$");
|
||||
return pattern.matcher(str).matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* EMOJI encode
|
||||
*
|
||||
* @param content 带有emoji表情的字符串
|
||||
* @return 将字符串中的emoji表情编码为UTF-8
|
||||
*/
|
||||
public static String emojiEncode(String content) {
|
||||
try {
|
||||
return RegexUtils.replaceAll(content, PatternEnum.EMOJI.getPattern(), a -> {
|
||||
try {
|
||||
return "[[EMOJI:" + URLEncoder.encode(a, "UTF-8") + "]]";
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new RuntimeException("emoji encode error");
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new RuntimeException("emoji filter error");
|
||||
}
|
||||
|
||||
/**
|
||||
* EMOJI decode
|
||||
*
|
||||
* @param content 字符串
|
||||
* @return 将带有编码后emoji的字符串 解码为emoji
|
||||
*/
|
||||
public static String emojiDecode(String content) {
|
||||
try {
|
||||
return RegexUtils.replaceAll(content, PatternEnum.EMOJI_DECODE.getPattern(), a -> {
|
||||
try {
|
||||
return URLDecoder.decode(a, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new RuntimeException("emoji decode error");
|
||||
}, 1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new RuntimeException("emoji decode error");
|
||||
}
|
||||
|
||||
public static String[] splitc(final String src, final char[] delimiters) {
|
||||
if ((delimiters.length == 0) || (src.isEmpty())) {
|
||||
return new String[] {src};
|
||||
}
|
||||
final char[] srcc = src.toCharArray();
|
||||
|
||||
final int maxparts = srcc.length + 1;
|
||||
final int[] start = new int[maxparts];
|
||||
final int[] end = new int[maxparts];
|
||||
|
||||
int count = 0;
|
||||
|
||||
start[0] = 0;
|
||||
int s = 0, e;
|
||||
if (CharUtil.equalsOne(srcc[0], delimiters)) { // string starts with delimiter
|
||||
end[0] = 0;
|
||||
count++;
|
||||
s = CharUtil.findFirstDiff(srcc, 1, delimiters);
|
||||
if (s == -1) { // nothing after delimiters
|
||||
return new String[] {EMPTY, EMPTY};
|
||||
}
|
||||
start[1] = s; // new start
|
||||
}
|
||||
while (true) {
|
||||
// find new end
|
||||
e = CharUtil.findFirstEqual(srcc, s, delimiters);
|
||||
if (e == -1) {
|
||||
end[count] = srcc.length;
|
||||
break;
|
||||
}
|
||||
end[count] = e;
|
||||
|
||||
// find new start
|
||||
count++;
|
||||
s = CharUtil.findFirstDiff(srcc, e, delimiters);
|
||||
if (s == -1) {
|
||||
start[count] = end[count] = srcc.length;
|
||||
break;
|
||||
}
|
||||
start[count] = s;
|
||||
}
|
||||
count++;
|
||||
final String[] result = new String[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
result[i] = src.substring(start[i], end[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String[] splitc(final String src, final char delimiter) {
|
||||
if (src.isEmpty()) {
|
||||
return new String[] {EMPTY};
|
||||
}
|
||||
final char[] srcc = src.toCharArray();
|
||||
|
||||
final int maxparts = srcc.length + 1;
|
||||
final int[] start = new int[maxparts];
|
||||
final int[] end = new int[maxparts];
|
||||
|
||||
int count = 0;
|
||||
|
||||
start[0] = 0;
|
||||
int s = 0, e;
|
||||
if (srcc[0] == delimiter) { // string starts with delimiter
|
||||
end[0] = 0;
|
||||
count++;
|
||||
s = CharUtil.findFirstDiff(srcc, 1, delimiter);
|
||||
if (s == -1) { // nothing after delimiters
|
||||
return new String[] {EMPTY, EMPTY};
|
||||
}
|
||||
start[1] = s; // new start
|
||||
}
|
||||
while (true) {
|
||||
// find new end
|
||||
e = CharUtil.findFirstEqual(srcc, s, delimiter);
|
||||
if (e == -1) {
|
||||
end[count] = srcc.length;
|
||||
break;
|
||||
}
|
||||
end[count] = e;
|
||||
|
||||
// find new start
|
||||
count++;
|
||||
s = CharUtil.findFirstDiff(srcc, e, delimiter);
|
||||
if (s == -1) {
|
||||
start[count] = end[count] = srcc.length;
|
||||
break;
|
||||
}
|
||||
start[count] = s;
|
||||
}
|
||||
count++;
|
||||
final String[] result = new String[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
result[i] = src.substring(start[i], end[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String[] splitc(final String src, final String d) {
|
||||
if ((d.isEmpty()) || (src.isEmpty())) {
|
||||
return new String[] {src};
|
||||
}
|
||||
return splitc(src, d.toCharArray());
|
||||
}
|
||||
|
||||
public static class MessageFormatter {
|
||||
static final char DELIM_START = '{';
|
||||
static final char DELIM_STOP = '}';
|
||||
static final String DELIM_STR = "{}";
|
||||
private static final char ESCAPE_CHAR = '\\';
|
||||
|
||||
static Throwable getThrowableCandidate(Object[] argArray) {
|
||||
if (argArray == null || argArray.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Object lastEntry = argArray[argArray.length - 1];
|
||||
if (lastEntry instanceof Throwable) {
|
||||
return (Throwable) lastEntry;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static FormattingTuple arrayFormat(final String messagePattern, final Object[] argArray) {
|
||||
Throwable throwableCandidate = getThrowableCandidate(argArray);
|
||||
Object[] args = argArray;
|
||||
if (throwableCandidate != null) {
|
||||
args = trimmedCopy(argArray);
|
||||
}
|
||||
return arrayFormat(messagePattern, args, throwableCandidate);
|
||||
}
|
||||
|
||||
private static Object[] trimmedCopy(Object[] argArray) {
|
||||
if (argArray == null || argArray.length == 0) {
|
||||
throw new IllegalStateException("non-sensical empty or null argument array");
|
||||
}
|
||||
final int trimemdLen = argArray.length - 1;
|
||||
Object[] trimmed = new Object[trimemdLen];
|
||||
System.arraycopy(argArray, 0, trimmed, 0, trimemdLen);
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
final public static FormattingTuple arrayFormat(final String messagePattern, final Object[] argArray,
|
||||
Throwable throwable) {
|
||||
|
||||
if (messagePattern == null) {
|
||||
return new FormattingTuple(null, argArray, throwable);
|
||||
}
|
||||
|
||||
if (argArray == null) {
|
||||
return new FormattingTuple(messagePattern);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
int j;
|
||||
// use string builder for better multicore performance
|
||||
StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50);
|
||||
|
||||
int L;
|
||||
for (L = 0; L < argArray.length; L++) {
|
||||
|
||||
j = messagePattern.indexOf(DELIM_STR, i);
|
||||
|
||||
if (j == -1) {
|
||||
// no more variables
|
||||
if (i == 0) { // this is a simple string
|
||||
return new FormattingTuple(messagePattern, argArray, throwable);
|
||||
} else { // add the tail string which contains no variables and return
|
||||
// the result.
|
||||
sbuf.append(messagePattern, i, messagePattern.length());
|
||||
return new FormattingTuple(sbuf.toString(), argArray, throwable);
|
||||
}
|
||||
} else {
|
||||
if (isEscapedDelimeter(messagePattern, j)) {
|
||||
if (!isDoubleEscaped(messagePattern, j)) {
|
||||
L--; // DELIM_START was escaped, thus should not be incremented
|
||||
sbuf.append(messagePattern, i, j - 1);
|
||||
sbuf.append(DELIM_START);
|
||||
i = j + 1;
|
||||
} else {
|
||||
// The escape character preceding the delimiter start is
|
||||
// itself escaped: "abc x:\\{}"
|
||||
// we have to consume one backward slash
|
||||
sbuf.append(messagePattern, i, j - 1);
|
||||
deeplyAppendParameter(sbuf, argArray[L], new HashMap<Object[], Object>());
|
||||
i = j + 2;
|
||||
}
|
||||
} else {
|
||||
// normal case
|
||||
sbuf.append(messagePattern, i, j);
|
||||
deeplyAppendParameter(sbuf, argArray[L], new HashMap<Object[], Object>());
|
||||
i = j + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
// append the characters following the last {} pair.
|
||||
sbuf.append(messagePattern, i, messagePattern.length());
|
||||
return new FormattingTuple(sbuf.toString(), argArray, throwable);
|
||||
}
|
||||
|
||||
final static boolean isEscapedDelimeter(String messagePattern, int delimeterStartIndex) {
|
||||
|
||||
if (delimeterStartIndex == 0) {
|
||||
return false;
|
||||
}
|
||||
char potentialEscape = messagePattern.charAt(delimeterStartIndex - 1);
|
||||
if (potentialEscape == ESCAPE_CHAR) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final static boolean isDoubleEscaped(String messagePattern, int delimeterStartIndex) {
|
||||
if (delimeterStartIndex >= 2 && messagePattern.charAt(delimeterStartIndex - 2) == ESCAPE_CHAR) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// special treatment of array values was suggested by 'lizongbo'
|
||||
private static void deeplyAppendParameter(StringBuilder sbuf, Object o, Map<Object[], Object> seenMap) {
|
||||
if (o == null) {
|
||||
sbuf.append("null");
|
||||
return;
|
||||
}
|
||||
if (!o.getClass().isArray()) {
|
||||
safeObjectAppend(sbuf, o);
|
||||
} else {
|
||||
// check for primitive array types because they
|
||||
// unfortunately cannot be cast to Object[]
|
||||
if (o instanceof boolean[]) {
|
||||
booleanArrayAppend(sbuf, (boolean[]) o);
|
||||
} else if (o instanceof byte[]) {
|
||||
byteArrayAppend(sbuf, (byte[]) o);
|
||||
} else if (o instanceof char[]) {
|
||||
charArrayAppend(sbuf, (char[]) o);
|
||||
} else if (o instanceof short[]) {
|
||||
shortArrayAppend(sbuf, (short[]) o);
|
||||
} else if (o instanceof int[]) {
|
||||
intArrayAppend(sbuf, (int[]) o);
|
||||
} else if (o instanceof long[]) {
|
||||
longArrayAppend(sbuf, (long[]) o);
|
||||
} else if (o instanceof float[]) {
|
||||
floatArrayAppend(sbuf, (float[]) o);
|
||||
} else if (o instanceof double[]) {
|
||||
doubleArrayAppend(sbuf, (double[]) o);
|
||||
} else {
|
||||
objectArrayAppend(sbuf, (Object[]) o, seenMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void safeObjectAppend(StringBuilder sbuf, Object o) {
|
||||
try {
|
||||
String oAsString = o.toString();
|
||||
sbuf.append(oAsString);
|
||||
} catch (Throwable t) {
|
||||
System.err.println("SLF4J: Failed toString() invocation on an object of type [" + o.getClass().getName() + "]");
|
||||
System.err.println("Reported exception:");
|
||||
t.printStackTrace();
|
||||
sbuf.append("[FAILED toString()]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void objectArrayAppend(StringBuilder sbuf, Object[] a, Map<Object[], Object> seenMap) {
|
||||
sbuf.append('[');
|
||||
if (!seenMap.containsKey(a)) {
|
||||
seenMap.put(a, null);
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
deeplyAppendParameter(sbuf, a[i], seenMap);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
// allow repeats in siblings
|
||||
seenMap.remove(a);
|
||||
} else {
|
||||
sbuf.append("...");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void booleanArrayAppend(StringBuilder sbuf, boolean[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void byteArrayAppend(StringBuilder sbuf, byte[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void charArrayAppend(StringBuilder sbuf, char[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void shortArrayAppend(StringBuilder sbuf, short[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void intArrayAppend(StringBuilder sbuf, int[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void longArrayAppend(StringBuilder sbuf, long[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void floatArrayAppend(StringBuilder sbuf, float[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void doubleArrayAppend(StringBuilder sbuf, double[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
}
|
||||
|
||||
public static String emojiFilter(String str) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
String patternString = "([\\x{10000}-\\x{10ffff}\ud800-\udfff])";
|
||||
|
||||
Pattern pattern = Pattern.compile(patternString);
|
||||
Matcher matcher = pattern.matcher(str);
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
try {
|
||||
matcher.appendReplacement(sb, "[[EMOJI:" + URLEncoder.encode(matcher.group(1), "UTF-8") + "]]");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String parseCurrency(String currency) {
|
||||
if (DataUtils.isEmpty(currency)) {
|
||||
return "";
|
||||
}
|
||||
switch (currency.toUpperCase()) {
|
||||
case "USD":
|
||||
return "$";
|
||||
case "EUR":
|
||||
return "€";
|
||||
case "CAD":
|
||||
return "CA$";
|
||||
case "GBP":
|
||||
return "£";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getExceptionStackTrace(Exception e) {
|
||||
try {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
return sw.toString();
|
||||
} catch (Exception ex) {
|
||||
return "bad get Error StackTrace From Exception";
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> split(String str, String reg) {
|
||||
return Arrays.stream(str.split(reg)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 逗号字符串 变成 long 的list
|
||||
*/
|
||||
public static List<Long> comma2LongList(String str) {
|
||||
if (DataUtils.isEmpty(str)) {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
return Splitter.on(",").omitEmptyStrings()
|
||||
.trimResults().splitToList(str.trim())
|
||||
.stream()
|
||||
.filter(NumberUtils::isDigits)
|
||||
.map(Long::parseLong).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 逗号字符串 变成 Integer 的list
|
||||
*/
|
||||
public static List<Integer> comma2IntegerList(String str) {
|
||||
if (DataUtils.isEmpty(str)) {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
return Splitter.on(",").omitEmptyStrings()
|
||||
.trimResults().splitToList(str.trim())
|
||||
.stream()
|
||||
.filter(NumberUtils::isDigits)
|
||||
.map(Integer::parseInt).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static List<String> comma2StringList(String str) {
|
||||
if (DataUtils.isEmpty(str)) {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
return Splitter.on(",").omitEmptyStrings().trimResults().splitToList(str.trim());
|
||||
}
|
||||
|
||||
public static <T> String joinCollection(Collection<T> originList) {
|
||||
return Joiner.on(",").join(originList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 xml 节点数据
|
||||
*
|
||||
* @param str xml
|
||||
* @param key TrackingNumber 不带 <>
|
||||
* @return java.lang.String
|
||||
* @author wh
|
||||
* @date 2021/6/10
|
||||
*/
|
||||
public static String parsXmlNode(String str, String key) {
|
||||
return parsXmlNode(str, key, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 xml节点
|
||||
*
|
||||
* @param str xml
|
||||
* @param key xml节点
|
||||
* @param index 相同节点第几个
|
||||
* @return
|
||||
*/
|
||||
public static String parsXmlNode(String str, String key, int index) {
|
||||
if (DataUtils.isEmpty(str) || DataUtils.isEmpty(key)) {
|
||||
return null;
|
||||
}
|
||||
key = String.join("", "<", key, ">");
|
||||
StringBuilder sb = new StringBuilder(key);
|
||||
sb.insert(1, "/");
|
||||
String regex = String.join("", key, "(.*?)", sb);
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher m = pattern.matcher(str);
|
||||
int count = 0;
|
||||
while (m.find()) {
|
||||
if (count == index) {
|
||||
return m.group(1);
|
||||
}
|
||||
++count;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断首字符是否为韩文
|
||||
*
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
public static boolean checkKoreaChar(String s) {
|
||||
if (DataUtils.isEmpty(s)) {
|
||||
return false;
|
||||
}
|
||||
char c = s.charAt(0);
|
||||
return (c > 0x3130 && c < 0x318F)
|
||||
|| (c >= 0xAC00 && c <= 0xD7A3);
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除字符串所有空格
|
||||
*/
|
||||
public static String trimAnySpace(String str) {
|
||||
return str.replaceAll("\\s*", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 首字母小写
|
||||
*/
|
||||
public static String firstLowerCase(String str) {
|
||||
if (DataUtils.isEmpty(str)) {
|
||||
return "";
|
||||
}
|
||||
var chars = str.toCharArray();
|
||||
chars[0] += 32;
|
||||
return String.valueOf(chars);
|
||||
}
|
||||
|
||||
/**
|
||||
* 首字母大写
|
||||
*/
|
||||
public static String firstUpperCase(String str) {
|
||||
if (DataUtils.isEmpty(str)) {
|
||||
return "";
|
||||
}
|
||||
char[] cs = str.toCharArray();
|
||||
cs[0] -= 32;
|
||||
return String.valueOf(cs);
|
||||
}
|
||||
|
||||
public static boolean equalsIgnoreCase(final CharSequence str1, final CharSequence str2) {
|
||||
return org.apache.commons.lang3.StringUtils.equalsIgnoreCase(str1, str2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断所有字符串是否都相等,null和1个也是返回true
|
||||
* <p>
|
||||
* System.out.println(allEquals(null)); true
|
||||
* System.out.println(allEquals(null, "1")); false
|
||||
* System.out.println(allEquals("1", null)); false
|
||||
* System.out.println(allEquals("1", "2")); false
|
||||
* System.out.println(allEquals("1", "1")); true
|
||||
* System.out.println(allEquals("1", "1", "3")); false
|
||||
* System.out.println(allEquals("1", "2", "3")); false
|
||||
* System.out.println(allEquals("1", "1", "1")); true
|
||||
*/
|
||||
public static boolean allEquals(String... strings) {
|
||||
if (null == strings) {
|
||||
return true;
|
||||
}
|
||||
String one = strings[0];
|
||||
for (int i = 1; i < strings.length; i++) {
|
||||
if (!Objects.equals(one, strings[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
|
||||
return org.apache.commons.lang3.StringUtils.defaultIfEmpty(str, defaultStr);
|
||||
}
|
||||
|
||||
public static <T extends CharSequence> T nullIfEmpty(final T str) {
|
||||
return org.apache.commons.lang3.StringUtils.defaultIfEmpty(str, null);
|
||||
}
|
||||
|
||||
public static String substringAfter(final String str, final String separator) {
|
||||
return org.apache.commons.lang3.StringUtils.substringAfter(str, separator);
|
||||
}
|
||||
|
||||
public static String toString(final Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
public static int indexOfChars(final String string, final String chars) {
|
||||
return indexOfChars(string, chars, 0);
|
||||
}
|
||||
|
||||
public static int indexOfChars(final String string, final String chars, int startindex) {
|
||||
final int stringLen = string.length();
|
||||
final int charsLen = chars.length();
|
||||
if (startindex < 0) {
|
||||
startindex = 0;
|
||||
}
|
||||
for (int i = startindex; i < stringLen; i++) {
|
||||
final char c = string.charAt(i);
|
||||
for (int j = 0; j < charsLen; j++) {
|
||||
if (c == chars.charAt(j)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static String replace(final String s, final String sub, final String with) {
|
||||
if (sub.isEmpty()) {
|
||||
return s;
|
||||
}
|
||||
int c = 0;
|
||||
int i = s.indexOf(sub, c);
|
||||
if (i == -1) {
|
||||
return s;
|
||||
}
|
||||
final int length = s.length();
|
||||
final StringBuilder sb = new StringBuilder(length + with.length());
|
||||
do {
|
||||
sb.append(s, c, i);
|
||||
sb.append(with);
|
||||
c = i + sub.length();
|
||||
}
|
||||
while ((i = s.indexOf(sub, c)) != -1);
|
||||
if (c < length) {
|
||||
sb.append(s, c, length);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static boolean startsWithChar(final String s, final char c) {
|
||||
if (s.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return s.charAt(0) == c;
|
||||
}
|
||||
|
||||
public static boolean containsOnlyDigitsAndSigns(final CharSequence string) {
|
||||
final int size = string.length();
|
||||
for (int i = 0; i < size; i++) {
|
||||
final char c = string.charAt(i);
|
||||
if ((!CharUtil.isDigit(c)) && (c != '-') && (c != '+')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean containsOnlyDigits(final CharSequence string) {
|
||||
final int size = string.length();
|
||||
for (int i = 0; i < size; i++) {
|
||||
final char c = string.charAt(i);
|
||||
if (!CharUtil.isDigit(c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String toHexString(final byte[] bytes) {
|
||||
final char[] chars = new char[bytes.length * 2];
|
||||
|
||||
int i = 0;
|
||||
for (final byte b : bytes) {
|
||||
chars[i++] = CharUtil.int2hex((b & 0xF0) >> 4);
|
||||
chars[i++] = CharUtil.int2hex(b & 0x0F);
|
||||
}
|
||||
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
public static String decapitalize(final String name) {
|
||||
if (name.isEmpty()) {
|
||||
return name;
|
||||
}
|
||||
if (name.length() > 1 &&
|
||||
Character.isUpperCase(name.charAt(1)) &&
|
||||
Character.isUpperCase(name.charAt(0))) {
|
||||
return name;
|
||||
}
|
||||
|
||||
final char[] chars = name.toCharArray();
|
||||
final char c = chars[0];
|
||||
final char modifiedChar = Character.toLowerCase(c);
|
||||
if (modifiedChar == c) {
|
||||
return name;
|
||||
}
|
||||
chars[0] = modifiedChar;
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
public static int count(final String source, final char c) {
|
||||
return count(source, c, 0);
|
||||
}
|
||||
|
||||
public static int count(final String source, final char c, final int start) {
|
||||
int count = 0;
|
||||
int j = start;
|
||||
while (true) {
|
||||
final int i = source.indexOf(c, j);
|
||||
if (i == -1) {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
j = i + 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static String repeat(final String source, int count) {
|
||||
final StringBuilder result = new StringBuilder(source.length() * count);
|
||||
while (count > 0) {
|
||||
result.append(source);
|
||||
count--;
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String repeat(final char c, final int count) {
|
||||
final char[] result = new char[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
result[i] = c;
|
||||
}
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,535 @@
|
|||
package com.nebula.base.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/11/18 13:56
|
||||
* @description:
|
||||
*/
|
||||
public class SystemInfo {
|
||||
|
||||
// ---------------------------------------------------------------- host
|
||||
|
||||
/**
|
||||
* Delegate host info to be resolved lazy.
|
||||
* Android detection will initialize this class too and since {@code InetAddress.getLocalHost()}
|
||||
* is forbidden in Android, we will get an exception.
|
||||
*/
|
||||
private static class HostInfoLazy {
|
||||
private final String HOST_NAME;
|
||||
private final String HOST_ADDRESS;
|
||||
|
||||
public HostInfoLazy() {
|
||||
String hostName;
|
||||
String hostAddress;
|
||||
|
||||
try {
|
||||
final InetAddress localhost = InetAddress.getLocalHost();
|
||||
|
||||
hostName = localhost.getHostName();
|
||||
hostAddress = localhost.getHostAddress();
|
||||
} catch (final UnknownHostException uhex) {
|
||||
hostName = "localhost";
|
||||
hostAddress = "127.0.0.2";
|
||||
}
|
||||
|
||||
this.HOST_NAME = hostName;
|
||||
this.HOST_ADDRESS = hostAddress;
|
||||
}
|
||||
}
|
||||
|
||||
private static HostInfoLazy hostInfoLazy;
|
||||
|
||||
/**
|
||||
* Returns host name.
|
||||
*/
|
||||
public final String getHostName() {
|
||||
if (hostInfoLazy == null) {
|
||||
hostInfoLazy = new HostInfoLazy();
|
||||
}
|
||||
return hostInfoLazy.HOST_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns host IP address.
|
||||
*/
|
||||
public final String getHostAddress() {
|
||||
if (hostInfoLazy == null) {
|
||||
hostInfoLazy = new HostInfoLazy();
|
||||
}
|
||||
return hostInfoLazy.HOST_ADDRESS;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- JVM
|
||||
|
||||
private final String JAVA_VM_NAME = SystemUtil.get("java.vm.name");
|
||||
private final String JAVA_VM_VERSION = SystemUtil.get("java.vm.version");
|
||||
private final String JAVA_VM_VENDOR = SystemUtil.get("java.vm.vendor");
|
||||
private final String JAVA_VM_INFO = SystemUtil.get("java.vm.info");
|
||||
private final String JAVA_VM_SPECIFICATION_NAME = SystemUtil.get("java.vm.specification.name");
|
||||
private final String JAVA_VM_SPECIFICATION_VERSION = SystemUtil.get("java.vm.specification.version");
|
||||
private final String JAVA_VM_SPECIFICATION_VENDOR = SystemUtil.get("java.vm.specification.vendor");
|
||||
|
||||
/**
|
||||
* Returns JVM name.
|
||||
*/
|
||||
public final String getJvmName() {
|
||||
return JAVA_VM_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns JVM version.
|
||||
*/
|
||||
public final String getJvmVersion() {
|
||||
return JAVA_VM_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns VM vendor.
|
||||
*/
|
||||
public final String getJvmVendor() {
|
||||
return JAVA_VM_VENDOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns additional VM information.
|
||||
*/
|
||||
public final String getJvmInfo() {
|
||||
return JAVA_VM_INFO;
|
||||
}
|
||||
|
||||
public final String getJvmSpecificationName() {
|
||||
return JAVA_VM_SPECIFICATION_NAME;
|
||||
}
|
||||
|
||||
public final String getJvmSpecificationVersion() {
|
||||
return JAVA_VM_SPECIFICATION_VERSION;
|
||||
}
|
||||
|
||||
public final String getJvmSpecificationVendor() {
|
||||
return JAVA_VM_SPECIFICATION_VENDOR;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- JAVA
|
||||
|
||||
private final String JAVA_VERSION = SystemUtil.get("java.version");
|
||||
private final int JAVA_VERSION_NUMBER = detectJavaVersionNumber();
|
||||
private final String JAVA_VENDOR = SystemUtil.get("java.vendor");
|
||||
private final String JAVA_VENDOR_URL = SystemUtil.get("java.vendor.url");
|
||||
private final String JAVA_SPECIFICATION_VERSION = SystemUtil.get("java.specification.version");
|
||||
private final String JAVA_SPECIFICATION_NAME = SystemUtil.get("java.specification.name");
|
||||
private final String JAVA_SPECIFICATION_VENDOR = SystemUtil.get("java.specification.vendor");
|
||||
private final String[] JRE_PACKAGES = buildJrePackages(JAVA_VERSION_NUMBER);
|
||||
|
||||
/**
|
||||
* Returns Java version string, as specified in system property.
|
||||
* Returned string contain major version, minor version and revision.
|
||||
*/
|
||||
public String getJavaVersion() {
|
||||
return JAVA_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns unified Java version as an integer.
|
||||
*/
|
||||
public int getJavaVersionNumber() {
|
||||
return JAVA_VERSION_NUMBER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Java vendor.
|
||||
*/
|
||||
public String getJavaVendor() {
|
||||
return JAVA_VENDOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Java vendor URL.
|
||||
*/
|
||||
public String getJavaVendorURL() {
|
||||
return JAVA_VENDOR_URL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the version of the currently running JVM.
|
||||
*/
|
||||
public String getJavaSpecificationVersion() {
|
||||
return JAVA_SPECIFICATION_VERSION;
|
||||
}
|
||||
|
||||
public final String getJavaSpecificationName() {
|
||||
return JAVA_SPECIFICATION_NAME;
|
||||
}
|
||||
|
||||
public final String getJavaSpecificationVendor() {
|
||||
return JAVA_SPECIFICATION_VENDOR;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- packages
|
||||
|
||||
/**
|
||||
* Returns list of packages, build into runtime jars.
|
||||
*/
|
||||
public String[] getJrePackages() {
|
||||
return JRE_PACKAGES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a set of java core packages.
|
||||
*/
|
||||
private String[] buildJrePackages(final int javaVersionNumber) {
|
||||
final ArrayList<String> packages = new ArrayList<>();
|
||||
|
||||
switch (javaVersionNumber) {
|
||||
case 9:
|
||||
case 8:
|
||||
case 7:
|
||||
case 6:
|
||||
case 5:
|
||||
// in Java1.5, the apache stuff moved
|
||||
packages.add("com.sun.org.apache");
|
||||
// fall through...
|
||||
case 4:
|
||||
if (javaVersionNumber == 4) {
|
||||
packages.add("org.apache.crimson");
|
||||
packages.add("org.apache.xalan");
|
||||
packages.add("org.apache.xml");
|
||||
packages.add("org.apache.xpath");
|
||||
}
|
||||
packages.add("org.ietf.jgss");
|
||||
packages.add("org.w3c.dom");
|
||||
packages.add("org.xml.sax");
|
||||
// fall through...
|
||||
case 3:
|
||||
packages.add("org.omg");
|
||||
packages.add("com.sun.corba");
|
||||
packages.add("com.sun.jndi");
|
||||
packages.add("com.sun.media");
|
||||
packages.add("com.sun.naming");
|
||||
packages.add("com.sun.org.omg");
|
||||
packages.add("com.sun.rmi");
|
||||
packages.add("sunw.io");
|
||||
packages.add("sunw.util");
|
||||
// fall through...
|
||||
case 2:
|
||||
packages.add("com.sun.java");
|
||||
packages.add("com.sun.image");
|
||||
// fall through...
|
||||
case 1:
|
||||
default:
|
||||
// core stuff
|
||||
packages.add("sun");
|
||||
packages.add("java");
|
||||
packages.add("javax");
|
||||
break;
|
||||
}
|
||||
|
||||
return packages.toArray(new String[0]);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------- java checks
|
||||
|
||||
private int detectJavaVersionNumber() {
|
||||
String javaVersion = JAVA_VERSION;
|
||||
|
||||
final int lastDashNdx = javaVersion.lastIndexOf('-');
|
||||
if (lastDashNdx != -1) {
|
||||
javaVersion = javaVersion.substring(0, lastDashNdx);
|
||||
}
|
||||
|
||||
if (javaVersion.startsWith("1.")) {
|
||||
// up to java 8
|
||||
final int index = javaVersion.indexOf('.', 2);
|
||||
return Integer.parseInt(javaVersion.substring(2, index));
|
||||
} else {
|
||||
final int index = javaVersion.indexOf('.');
|
||||
return Integer.parseInt(index == -1 ? javaVersion : javaVersion.substring(0, index));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the currently running JVM is at least compliant
|
||||
* with provided JDK version.
|
||||
*/
|
||||
public boolean isAtLeastJavaVersion(final int version) {
|
||||
return JAVA_VERSION_NUMBER >= version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the currently running JVM is equal to provided version.
|
||||
*/
|
||||
public boolean isJavaVersion(final int version) {
|
||||
return JAVA_VERSION_NUMBER == version;
|
||||
}
|
||||
|
||||
|
||||
private final String OS_VERSION = SystemUtil.get("os.version");
|
||||
private final String OS_ARCH = SystemUtil.get("os.arch");
|
||||
private final String OS_NAME = SystemUtil.get("os.name");
|
||||
|
||||
private final boolean IS_ANDROID = isAndroid0();
|
||||
private final boolean IS_OS_AIX = matchOS("AIX");
|
||||
private final boolean IS_OS_HP_UX = matchOS("HP-UX");
|
||||
private final boolean IS_OS_IRIX = matchOS("Irix");
|
||||
private final boolean IS_OS_LINUX = matchOS("Linux") || matchOS("LINUX");
|
||||
private final boolean IS_OS_MAC = matchOS("Mac");
|
||||
private final boolean IS_OS_MAC_OSX = matchOS("Mac OS X");
|
||||
private final boolean IS_OS_OS2 = matchOS("OS/2");
|
||||
private final boolean IS_OS_SOLARIS = matchOS("Solaris");
|
||||
private final boolean IS_OS_SUN_OS = matchOS("SunOS");
|
||||
private final boolean IS_OS_WINDOWS = matchOS("Windows");
|
||||
private final boolean IS_OS_WINDOWS_2000 = matchOS("Windows", "5.0");
|
||||
private final boolean IS_OS_WINDOWS_95 = matchOS("Windows 9", "4.0");
|
||||
private final boolean IS_OS_WINDOWS_98 = matchOS("Windows 9", "4.1");
|
||||
private final boolean IS_OS_WINDOWS_ME = matchOS("Windows", "4.9");
|
||||
private final boolean IS_OS_WINDOWS_NT = matchOS("Windows NT");
|
||||
private final boolean IS_OS_WINDOWS_XP = matchOS("Windows", "5.1");
|
||||
|
||||
private final String FILE_SEPARATOR = SystemUtil.get("file.separator");
|
||||
private final String LINE_SEPARATOR = SystemUtil.get("line.separator");
|
||||
private final String PATH_SEPARATOR = SystemUtil.get("path.separator");
|
||||
private final String FILE_ENCODING = SystemUtil.get("file.encoding");
|
||||
|
||||
public final String getOsArchitecture() {
|
||||
return OS_ARCH;
|
||||
}
|
||||
|
||||
public final String getOsName() {
|
||||
return OS_NAME;
|
||||
}
|
||||
|
||||
public final String getOsVersion() {
|
||||
return OS_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if system is android.
|
||||
*/
|
||||
public boolean isAndroid() {
|
||||
return IS_ANDROID;
|
||||
}
|
||||
|
||||
private static boolean isAndroid0() {
|
||||
try {
|
||||
Class.forName("android.app.Application", false, ClassLoaderUtil.getSystemClassLoader());
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public final boolean isAix() {
|
||||
return IS_OS_AIX;
|
||||
}
|
||||
|
||||
public final boolean isHpUx() {
|
||||
return IS_OS_HP_UX;
|
||||
}
|
||||
|
||||
public final boolean isIrix() {
|
||||
return IS_OS_IRIX;
|
||||
}
|
||||
|
||||
public final boolean isLinux() {
|
||||
return IS_OS_LINUX;
|
||||
}
|
||||
|
||||
public final boolean isMac() {
|
||||
return IS_OS_MAC;
|
||||
}
|
||||
|
||||
public final boolean isMacOsX() {
|
||||
return IS_OS_MAC_OSX;
|
||||
}
|
||||
|
||||
public final boolean isOs2() {
|
||||
return IS_OS_OS2;
|
||||
}
|
||||
|
||||
public final boolean isSolaris() {
|
||||
return IS_OS_SOLARIS;
|
||||
}
|
||||
|
||||
public final boolean isSunOS() {
|
||||
return IS_OS_SUN_OS;
|
||||
}
|
||||
|
||||
public final boolean isWindows() {
|
||||
return IS_OS_WINDOWS;
|
||||
}
|
||||
|
||||
public final boolean isWindows2000() {
|
||||
return IS_OS_WINDOWS_2000;
|
||||
}
|
||||
|
||||
public final boolean isWindows95() {
|
||||
return IS_OS_WINDOWS_95;
|
||||
}
|
||||
|
||||
public final boolean isWindows98() {
|
||||
return IS_OS_WINDOWS_98;
|
||||
}
|
||||
|
||||
public final boolean isWindowsME() {
|
||||
return IS_OS_WINDOWS_ME;
|
||||
}
|
||||
|
||||
public final boolean isWindowsNT() {
|
||||
return IS_OS_WINDOWS_NT;
|
||||
}
|
||||
|
||||
public final boolean isWindowsXP() {
|
||||
return IS_OS_WINDOWS_XP;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- file
|
||||
|
||||
public final String getFileSeparator() {
|
||||
return FILE_SEPARATOR;
|
||||
}
|
||||
|
||||
public final String getLineSeparator() {
|
||||
return LINE_SEPARATOR;
|
||||
}
|
||||
|
||||
public final String getPathSeparator() {
|
||||
return PATH_SEPARATOR;
|
||||
}
|
||||
|
||||
public final String getFileEncoding() {
|
||||
return FILE_ENCODING;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- util
|
||||
|
||||
private boolean matchOS(final String osNamePrefix) {
|
||||
if (OS_NAME == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return OS_NAME.startsWith(osNamePrefix);
|
||||
}
|
||||
|
||||
private boolean matchOS(final String osNamePrefix, final String osVersionPrefix) {
|
||||
if ((OS_NAME == null) || (OS_VERSION == null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return OS_NAME.startsWith(osNamePrefix) && OS_VERSION.startsWith(osVersionPrefix);
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- runtime
|
||||
|
||||
private final Runtime runtime = Runtime.getRuntime();
|
||||
|
||||
/**
|
||||
* Returns MAX memory.
|
||||
*/
|
||||
public final long getMaxMemory(){
|
||||
return runtime.maxMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TOTAL memory.
|
||||
*/
|
||||
public final long getTotalMemory(){
|
||||
return runtime.totalMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns FREE memory.
|
||||
*/
|
||||
public final long getFreeMemory(){
|
||||
return runtime.freeMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns usable memory.
|
||||
*/
|
||||
public final long getAvailableMemory(){
|
||||
return runtime.maxMemory() - runtime.totalMemory() + runtime.freeMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns used memory.
|
||||
*/
|
||||
public final long getUsedMemory(){
|
||||
return runtime.totalMemory() - runtime.freeMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns PID of current Java process.
|
||||
*/
|
||||
public final long getCurrentPID() {
|
||||
return Long.parseLong(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of CPUs.
|
||||
*/
|
||||
public final long getCPUs() {
|
||||
return runtime.availableProcessors();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- user
|
||||
|
||||
|
||||
private final String USER_NAME = SystemUtil.get("user.name");
|
||||
private final String USER_HOME = nosep(SystemUtil.get("user.home"));
|
||||
private final String USER_DIR = nosep(SystemUtil.get("user.dir"));
|
||||
private final String USER_LANGUAGE = SystemUtil.get("user.language");
|
||||
private final String USER_COUNTRY = ((SystemUtil.get("user.country") == null) ? SystemUtil.get("user.region") : SystemUtil.get("user.country"));
|
||||
private final String JAVA_IO_TMPDIR = SystemUtil.get("java.io.tmpdir");
|
||||
private final String JAVA_HOME = nosep(SystemUtil.get("java.home"));
|
||||
private final String[] SYSTEM_CLASS_PATH = StringUtils.splitc(SystemUtil.get("java.class.path"), File.pathSeparator);
|
||||
|
||||
public final String getUserName() {
|
||||
return USER_NAME;
|
||||
}
|
||||
|
||||
public final String getHomeDir() {
|
||||
return USER_HOME;
|
||||
}
|
||||
|
||||
public final String getWorkingDir() {
|
||||
return USER_DIR;
|
||||
}
|
||||
|
||||
public final String getTempDir() {
|
||||
return JAVA_IO_TMPDIR;
|
||||
}
|
||||
|
||||
public final String getUserLanguage() {
|
||||
return USER_LANGUAGE;
|
||||
}
|
||||
|
||||
public final String getUserCountry() {
|
||||
return USER_COUNTRY;
|
||||
}
|
||||
|
||||
public String getJavaHomeDir() {
|
||||
return JAVA_HOME;
|
||||
}
|
||||
|
||||
public String[] getSystemClasspath() {
|
||||
return SYSTEM_CLASS_PATH;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- util
|
||||
|
||||
protected String nosep(final String in) {
|
||||
if (in.endsWith(File.separator)) {
|
||||
return in.substring(0, in.length() - 1);
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
package com.nebula.base.utils;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/11/18 11:28
|
||||
* @description:
|
||||
*/
|
||||
public class SystemUtil {
|
||||
|
||||
/**
|
||||
* Returns system property or {@code null} if not set.
|
||||
*/
|
||||
public static String get(final String name) {
|
||||
return get(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns system property. If key is not available, returns the default value.
|
||||
*/
|
||||
public static String get(final String name, final String defaultValue) {
|
||||
Objects.requireNonNull(name);
|
||||
|
||||
String value = null;
|
||||
try {
|
||||
if (System.getSecurityManager() == null) {
|
||||
value = System.getProperty(name);
|
||||
} else {
|
||||
value = AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty(name));
|
||||
}
|
||||
} catch (final Exception ignore) {
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns system property as boolean.
|
||||
*/
|
||||
public static boolean getBoolean(final String name, final boolean defaultValue) {
|
||||
String value = get(name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
value = value.trim().toLowerCase();
|
||||
|
||||
switch (value) {
|
||||
case "true":
|
||||
case "yes":
|
||||
case "1":
|
||||
case "on":
|
||||
return true;
|
||||
case "false":
|
||||
case "no":
|
||||
case "0":
|
||||
case "off":
|
||||
return false;
|
||||
default:
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns system property as an int.
|
||||
*/
|
||||
public static long getInt(final String name, final int defaultValue) {
|
||||
String value = get(name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
value = value.trim().toLowerCase();
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (final NumberFormatException nfex) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns system property as a long.
|
||||
*/
|
||||
public static long getLong(final String name, final long defaultValue) {
|
||||
String value = get(name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
value = value.trim().toLowerCase();
|
||||
try {
|
||||
return Long.parseLong(value);
|
||||
} catch (final NumberFormatException nfex) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取CPU核数
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static int getCPU() {
|
||||
return Runtime.getRuntime().availableProcessors();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- infos
|
||||
|
||||
private static final SystemInfo systemInfo = new SystemInfo();
|
||||
|
||||
/**
|
||||
* Returns system information.
|
||||
*/
|
||||
public static SystemInfo info() {
|
||||
return systemInfo;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.nebula.base.utils;
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/11/18 11:24
|
||||
* @description: 线程创建工厂
|
||||
*/
|
||||
@Slf4j
|
||||
public class ThreadFactoryImpl implements ThreadFactory {
|
||||
|
||||
private final AtomicLong threadIndex = new AtomicLong(0);
|
||||
private final String threadNamePrefix;
|
||||
private final boolean daemon;
|
||||
|
||||
public ThreadFactoryImpl(final String threadNamePrefix) {
|
||||
this(threadNamePrefix, false);
|
||||
}
|
||||
|
||||
public ThreadFactoryImpl(final String threadNamePrefix, boolean daemon) {
|
||||
this.threadNamePrefix = threadNamePrefix;
|
||||
this.daemon = daemon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread thread = new Thread(r, threadNamePrefix + this.threadIndex.incrementAndGet());
|
||||
thread.setDaemon(daemon);
|
||||
|
||||
thread.setUncaughtExceptionHandler((t, e) ->
|
||||
log.error("Thread has an uncaught exception, threadId={}, threadName={}",
|
||||
t.getId(), t.getName(), e));
|
||||
|
||||
return thread;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
package com.nebula.base.utils;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/11/18 11:27
|
||||
* @description:
|
||||
*/
|
||||
public class ThreadPoolBuilder {
|
||||
|
||||
private static final RejectedExecutionHandler defaultRejectHandler = new ThreadPoolExecutor.AbortPolicy();
|
||||
|
||||
/**
|
||||
* cpu核数
|
||||
*/
|
||||
private static final int CPU = SystemUtil.getCPU();
|
||||
|
||||
/**
|
||||
* create io ThreadPoolExecutor
|
||||
*
|
||||
* @return ThreadPoolExecutor
|
||||
*/
|
||||
public static IOThreadPoolBuilder ioThreadPoolBuilder() {
|
||||
return new IOThreadPoolBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* create cpu ThreadPoolExecutor
|
||||
*
|
||||
* @return ThreadPoolExecutor
|
||||
*/
|
||||
public static CPUThreadPoolBuilder cpuThreadPoolBuilder() {
|
||||
return new CPUThreadPoolBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* IO 类型线程池
|
||||
*/
|
||||
public static class IOThreadPoolBuilder {
|
||||
|
||||
private ThreadFactory threadFactory;
|
||||
|
||||
private RejectedExecutionHandler rejectHandler;
|
||||
|
||||
private int queueSize = -1;
|
||||
|
||||
private int maximumPoolSize = CPU;
|
||||
|
||||
private int keepAliveTime = 120;
|
||||
|
||||
private boolean daemon = false;
|
||||
|
||||
private String threadNamePrefix;
|
||||
|
||||
public int getCorePooSize(int ioTime, int cpuTime) {
|
||||
return CPU + (1 + (ioTime / cpuTime));
|
||||
}
|
||||
|
||||
public IOThreadPoolBuilder setThreadNamePrefix(String threadNamePrefix) {
|
||||
this.threadNamePrefix = threadNamePrefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IOThreadPoolBuilder setDaemon(boolean daemon) {
|
||||
this.daemon = daemon;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IOThreadPoolBuilder setRejectHandler(RejectedExecutionHandler rejectHandler) {
|
||||
this.rejectHandler = rejectHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IOThreadPoolBuilder setQueueSize(int queueSize) {
|
||||
this.queueSize = queueSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IOThreadPoolBuilder setMaximumPoolSize(int maximumPoolSize) {
|
||||
this.maximumPoolSize = maximumPoolSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IOThreadPoolBuilder setKeepAliveTime(int keepAliveTime) {
|
||||
this.keepAliveTime = keepAliveTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThreadPoolExecutor builder(int ioTime, int cpuTime) {
|
||||
BlockingQueue<Runnable> queue;
|
||||
|
||||
if (rejectHandler == null) {
|
||||
rejectHandler = defaultRejectHandler;
|
||||
}
|
||||
threadFactory = new ThreadFactoryImpl(this.threadNamePrefix, this.daemon);
|
||||
|
||||
queue = queueSize < 1 ? new LinkedBlockingQueue<>() : new ArrayBlockingQueue<>(queueSize);
|
||||
|
||||
return new ThreadPoolExecutor(getCorePooSize(ioTime, cpuTime), maximumPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, queue, threadFactory, rejectHandler);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* CPU 类型线程池
|
||||
*/
|
||||
public static class CPUThreadPoolBuilder {
|
||||
|
||||
private ThreadFactory threadFactory;
|
||||
|
||||
private RejectedExecutionHandler rejectHandler;
|
||||
|
||||
private int queueSize = -1;
|
||||
|
||||
private int maximumPoolSize = CPU;
|
||||
|
||||
private int keepAliveTime = 120;
|
||||
|
||||
private boolean daemon = false;
|
||||
|
||||
private String threadNamePrefix;
|
||||
|
||||
public int getCorePooSize() {
|
||||
return CPU;
|
||||
}
|
||||
|
||||
public CPUThreadPoolBuilder setThreadNamePrefix(String threadNamePrefix) {
|
||||
this.threadNamePrefix = threadNamePrefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CPUThreadPoolBuilder setDaemon(boolean daemon) {
|
||||
this.daemon = daemon;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CPUThreadPoolBuilder setRejectHandler(RejectedExecutionHandler rejectHandler) {
|
||||
this.rejectHandler = rejectHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CPUThreadPoolBuilder setQueueSize(int queueSize) {
|
||||
this.queueSize = queueSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CPUThreadPoolBuilder setMaximumPoolSize(int maximumPoolSize) {
|
||||
this.maximumPoolSize = maximumPoolSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CPUThreadPoolBuilder setKeepAliveTime(int keepAliveTime) {
|
||||
this.keepAliveTime = keepAliveTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThreadPoolExecutor builder() {
|
||||
if (rejectHandler == null) {
|
||||
rejectHandler = defaultRejectHandler;
|
||||
}
|
||||
threadFactory = new ThreadFactoryImpl(this.threadNamePrefix, this.daemon);
|
||||
|
||||
BlockingQueue<Runnable> queue = queueSize < 1 ? new LinkedBlockingQueue<>() : new ArrayBlockingQueue<>(queueSize);
|
||||
|
||||
return new ThreadPoolExecutor(getCorePooSize(), maximumPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, queue, threadFactory, rejectHandler);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -23,7 +23,7 @@ public class TimeUtil {
|
|||
|
||||
public static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern(YYYYMMdd);
|
||||
|
||||
public static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern(HHmmss);
|
||||
public static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern(HHmmss);
|
||||
|
||||
public static LocalDateTime toLocalDateTime(long unixTime, Integer zoneOffset) {
|
||||
Instant instant = Instant.ofEpochMilli(unixTime);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,604 @@
|
|||
package com.nebula.base.utils.io;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.CharArrayWriter;
|
||||
import java.io.Closeable;
|
||||
import java.io.Flushable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2022/1/14 13:42
|
||||
* @description:
|
||||
*/
|
||||
public class IOUtil {
|
||||
|
||||
/**
|
||||
* Buffer size for various I/O operations.
|
||||
*/
|
||||
public static int ioBufferSize = 16384;
|
||||
|
||||
private static final int ZERO = 0;
|
||||
private static final int NEGATIVE_ONE = -1;
|
||||
private static final int ALL = -1;
|
||||
|
||||
// ---------------------------------------------------------------- silent close
|
||||
|
||||
/**
|
||||
* Closes silently the closable object. If it is {@link Flushable}, it
|
||||
* will be flushed first. No exception will be thrown if an I/O error occurs.
|
||||
*/
|
||||
public static void close(final Closeable closeable) {
|
||||
if (closeable != null) {
|
||||
if (closeable instanceof Flushable) {
|
||||
try {
|
||||
((Flushable) closeable).flush();
|
||||
} catch (final IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (final IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- copy
|
||||
|
||||
/**
|
||||
* Copies bytes from {@link Reader} to {@link Writer} using buffer.
|
||||
* {@link Reader} and {@link Writer} don't have to be wrapped to buffered, since copying is already optimized.
|
||||
*
|
||||
* @param input {@link Reader} to read.
|
||||
* @param output {@link Writer} to write to.
|
||||
* @return The total number of characters read.
|
||||
* @throws IOException if there is an error reading or writing.
|
||||
*/
|
||||
public static int copy(final Reader input, final Writer output) throws IOException {
|
||||
final int numToRead = bufferSize();
|
||||
final char[] buffer = new char[numToRead];
|
||||
|
||||
int totalRead = ZERO;
|
||||
int read;
|
||||
|
||||
while ((read = input.read(buffer, ZERO, numToRead)) >= ZERO) {
|
||||
output.write(buffer, ZERO, read);
|
||||
totalRead = totalRead + read;
|
||||
}
|
||||
|
||||
output.flush();
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies bytes from {@link InputStream} to {@link OutputStream} using buffer.
|
||||
* {@link InputStream} and {@link OutputStream} don't have to be wrapped to buffered,
|
||||
* since copying is already optimized.
|
||||
*
|
||||
* @param input {@link InputStream} to read.
|
||||
* @param output {@link OutputStream} to write to.
|
||||
* @return The total number of bytes read.
|
||||
* @throws IOException if there is an error reading or writing.
|
||||
*/
|
||||
public static int copy(final InputStream input, final OutputStream output) throws IOException {
|
||||
final int numToRead = bufferSize();
|
||||
final byte[] buffer = new byte[numToRead];
|
||||
|
||||
int totalRead = ZERO;
|
||||
int read;
|
||||
|
||||
while ((read = input.read(buffer, ZERO, numToRead)) >= ZERO) {
|
||||
output.write(buffer, ZERO, read);
|
||||
totalRead = totalRead + read;
|
||||
}
|
||||
|
||||
output.flush();
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies specified number of characters from {@link Reader} to {@link Writer} using buffer.
|
||||
* {@link Reader} and {@link Writer} don't have to be wrapped to buffered, since copying is already optimized.
|
||||
*
|
||||
* @param input {@link Reader} to read.
|
||||
* @param output {@link Writer} to write to.
|
||||
* @param count The number of characters to read.
|
||||
* @return The total number of characters read.
|
||||
* @throws IOException if there is an error reading or writing.
|
||||
*/
|
||||
public static int copy(final Reader input, final Writer output, final int count) throws IOException {
|
||||
if (count == ALL) {
|
||||
return copy(input, output);
|
||||
}
|
||||
|
||||
int numToRead = count;
|
||||
final char[] buffer = new char[numToRead];
|
||||
|
||||
int totalRead = ZERO;
|
||||
int read;
|
||||
|
||||
while (numToRead > ZERO) {
|
||||
read = input.read(buffer, ZERO, bufferSize(numToRead));
|
||||
if (read == NEGATIVE_ONE) {
|
||||
break;
|
||||
}
|
||||
output.write(buffer, ZERO, read);
|
||||
|
||||
numToRead = numToRead - read;
|
||||
totalRead = totalRead + read;
|
||||
}
|
||||
|
||||
output.flush();
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies specified number of bytes from {@link InputStream} to {@link OutputStream} using buffer.
|
||||
* {@link InputStream} and {@link OutputStream} don't have to be wrapped to buffered, since copying is already optimized.
|
||||
*
|
||||
* @param input {@link InputStream} to read.
|
||||
* @param output {@link OutputStream} to write to.
|
||||
* @param count The number of bytes to read.
|
||||
* @return The total number of bytes read.
|
||||
* @throws IOException if there is an error reading or writing.
|
||||
*/
|
||||
public static int copy(final InputStream input, final OutputStream output, final int count) throws IOException {
|
||||
if (count == ALL) {
|
||||
return copy(input, output);
|
||||
}
|
||||
|
||||
int numToRead = count;
|
||||
final byte[] buffer = new byte[numToRead];
|
||||
|
||||
int totalRead = ZERO;
|
||||
int read;
|
||||
|
||||
while (numToRead > ZERO) {
|
||||
read = input.read(buffer, ZERO, bufferSize(numToRead));
|
||||
if (read == NEGATIVE_ONE) {
|
||||
break;
|
||||
}
|
||||
output.write(buffer, ZERO, read);
|
||||
|
||||
numToRead = numToRead - read;
|
||||
totalRead = totalRead + read;
|
||||
}
|
||||
|
||||
output.flush();
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- read bytes
|
||||
|
||||
/**
|
||||
* Reads all available bytes from {@link InputStream} as a byte array.
|
||||
* Uses {@link InputStream#available()} to determine the size of input stream.
|
||||
* This is the fastest method for reading {@link InputStream} to byte array, but
|
||||
* depends on {@link InputStream} implementation of {@link InputStream#available()}.
|
||||
*
|
||||
* @param input {@link InputStream} to read.
|
||||
* @return byte[]
|
||||
* @throws IOException if total read is less than {@link InputStream#available()};
|
||||
*/
|
||||
public static byte[] readAvailableBytes(final InputStream input) throws IOException {
|
||||
final int numToRead = input.available();
|
||||
final byte[] buffer = new byte[numToRead];
|
||||
|
||||
int totalRead = ZERO;
|
||||
int read;
|
||||
|
||||
while ((totalRead < numToRead) && (read = input.read(buffer, totalRead, numToRead - totalRead)) >= ZERO) {
|
||||
totalRead = totalRead + read;
|
||||
}
|
||||
|
||||
if (totalRead < numToRead) {
|
||||
throw new IOException("Failed to completely read InputStream");
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- copy to OutputStream
|
||||
|
||||
/**
|
||||
* @see #copy(Reader, OutputStream, Charset)
|
||||
*/
|
||||
public static <T extends OutputStream> T copy(final Reader input, final T output) throws IOException {
|
||||
return copy(input, output, encoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copy(Reader, OutputStream, Charset, int)
|
||||
*/
|
||||
public static <T extends OutputStream> T copy(final Reader input, final T output, final int count) throws IOException {
|
||||
return copy(input, output, encoding(), count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copy(Reader, OutputStream, Charset, int)
|
||||
*/
|
||||
public static <T extends OutputStream> T copy(final Reader input, final T output, final Charset encoding) throws IOException {
|
||||
return copy(input, output, encoding, ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies {@link Reader} to {@link OutputStream} using buffer and specified encoding.
|
||||
*
|
||||
* @see #copy(Reader, Writer, int)
|
||||
*/
|
||||
public static <T extends OutputStream> T copy(final Reader input, final T output, final Charset encoding, final int count) throws IOException {
|
||||
try (final Writer out = outputStreamWriterOf(output, encoding)) {
|
||||
copy(input, out, count);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copyToOutputStream(InputStream, int)
|
||||
*/
|
||||
public static ByteArrayOutputStream copyToOutputStream(final InputStream input) throws IOException {
|
||||
return copyToOutputStream(input, ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies {@link InputStream} to a new {@link ByteArrayOutputStream} using buffer and specified encoding.
|
||||
*
|
||||
* @see #copy(InputStream, OutputStream, int)
|
||||
*/
|
||||
public static ByteArrayOutputStream copyToOutputStream(final InputStream input, final int count) throws IOException {
|
||||
try (final ByteArrayOutputStream output = createFastByteArrayOutputStream()) {
|
||||
copy(input, output, count);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copyToOutputStream(Reader, Charset)
|
||||
*/
|
||||
public static ByteArrayOutputStream copyToOutputStream(final Reader input) throws IOException {
|
||||
return copyToOutputStream(input, encoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copyToOutputStream(Reader, Charset, int)
|
||||
*/
|
||||
public static ByteArrayOutputStream copyToOutputStream(final Reader input, final Charset encoding) throws IOException {
|
||||
return copyToOutputStream(input, encoding, ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copyToOutputStream(Reader, Charset, int)
|
||||
*/
|
||||
public static ByteArrayOutputStream copyToOutputStream(final Reader input, final int count) throws IOException {
|
||||
return copyToOutputStream(input, encoding(), count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies {@link Reader} to a new {@link ByteArrayOutputStream} using buffer and specified encoding.
|
||||
*
|
||||
* @see #copy(Reader, OutputStream, Charset, int)
|
||||
*/
|
||||
public static ByteArrayOutputStream copyToOutputStream(final Reader input, final Charset encoding, final int count) throws IOException {
|
||||
try (final ByteArrayOutputStream output = createFastByteArrayOutputStream()) {
|
||||
copy(input, output, encoding, count);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- copy to Writer
|
||||
|
||||
/**
|
||||
* @see #copy(InputStream, Writer, Charset)
|
||||
*/
|
||||
public static <T extends Writer> T copy(final InputStream input, final T output) throws IOException {
|
||||
return copy(input, output, encoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copy(InputStream, Writer, Charset, int)
|
||||
*/
|
||||
public static <T extends Writer> T copy(final InputStream input, final T output, final int count) throws IOException {
|
||||
return copy(input, output, encoding(), count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copy(InputStream, Writer, Charset, int)
|
||||
*/
|
||||
public static <T extends Writer> T copy(final InputStream input, final T output, final Charset encoding) throws IOException {
|
||||
return copy(input, output, encoding, ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies {@link InputStream} to {@link Writer} using buffer and specified encoding.
|
||||
*
|
||||
* @see #copy(Reader, Writer, int)
|
||||
*/
|
||||
public static <T extends Writer> T copy(final InputStream input, final T output, final Charset encoding, final int count) throws IOException {
|
||||
copy(inputStreamReadeOf(input, encoding), output, count);
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copy(InputStream, Charset)
|
||||
*/
|
||||
public static CharArrayWriter copy(final InputStream input) throws IOException {
|
||||
return copy(input, encoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copy(InputStream, Charset, int)
|
||||
*/
|
||||
public static CharArrayWriter copy(final InputStream input, final int count) throws IOException {
|
||||
return copy(input, encoding(), count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copy(InputStream, Charset, int)
|
||||
*/
|
||||
public static CharArrayWriter copy(final InputStream input, final Charset encoding) throws IOException {
|
||||
return copy(input, encoding, ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies {@link InputStream} to a new {@link CharArrayWriter} using buffer and specified encoding.
|
||||
*
|
||||
* @see #copy(InputStream, Writer, Charset, int)
|
||||
*/
|
||||
public static CharArrayWriter copy(final InputStream input, final Charset encoding, final int count) throws IOException {
|
||||
try (final CharArrayWriter output = createFastCharArrayWriter()) {
|
||||
copy(input, output, encoding, count);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copy(Reader, int)
|
||||
*/
|
||||
public static CharArrayWriter copy(final Reader input) throws IOException {
|
||||
return copy(input, ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies {@link Reader} to a new {@link CharArrayWriter} using buffer and specified encoding.
|
||||
*
|
||||
* @see #copy(Reader, Writer, int)
|
||||
*/
|
||||
public static CharArrayWriter copy(final Reader input, final int count) throws IOException {
|
||||
try (final CharArrayWriter output = createFastCharArrayWriter()) {
|
||||
copy(input, output, count);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- read bytes
|
||||
|
||||
/**
|
||||
* @see #readBytes(InputStream, int)
|
||||
*/
|
||||
public static byte[] readBytes(final InputStream input) throws IOException {
|
||||
return readBytes(input, ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copyToOutputStream(InputStream, int)
|
||||
*/
|
||||
public static byte[] readBytes(final InputStream input, final int count) throws IOException {
|
||||
return copyToOutputStream(input, count).toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #readBytes(Reader, Charset)
|
||||
*/
|
||||
public static byte[] readBytes(final Reader input) throws IOException {
|
||||
return readBytes(input, encoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #readBytes(Reader, Charset, int)
|
||||
*/
|
||||
public static byte[] readBytes(final Reader input, final int count) throws IOException {
|
||||
return readBytes(input, encoding(), count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #readBytes(Reader, Charset, int)
|
||||
*/
|
||||
public static byte[] readBytes(final Reader input, final Charset encoding) throws IOException {
|
||||
return readBytes(input, encoding, ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copyToOutputStream(Reader, Charset, int)
|
||||
*/
|
||||
public static byte[] readBytes(final Reader input, final Charset encoding, final int count) throws IOException {
|
||||
return copyToOutputStream(input, encoding, count).toByteArray();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- read chars
|
||||
|
||||
/**
|
||||
* @see #readChars(Reader, int)
|
||||
*/
|
||||
public static char[] readChars(final Reader input) throws IOException {
|
||||
return readChars(input, ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copy(Reader, int)
|
||||
*/
|
||||
public static char[] readChars(final Reader input, final int count) throws IOException {
|
||||
return copy(input, count).toCharArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #readChars(InputStream, int)
|
||||
*/
|
||||
public static char[] readChars(final InputStream input) throws IOException {
|
||||
return readChars(input, ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #readChars(InputStream, Charset, int)
|
||||
*/
|
||||
public static char[] readChars(final InputStream input, final Charset encoding) throws IOException {
|
||||
return readChars(input, encoding, ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #readChars(InputStream, Charset, int)
|
||||
*/
|
||||
public static char[] readChars(final InputStream input, final int count) throws IOException {
|
||||
return readChars(input, encoding(), count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #copy(InputStream, Charset, int)
|
||||
*/
|
||||
public static char[] readChars(final InputStream input, final Charset encoding, final int count) throws IOException {
|
||||
return copy(input, encoding, count).toCharArray();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- compare content
|
||||
|
||||
/**
|
||||
* Compares the content of two byte streams ({@link InputStream}s).
|
||||
*
|
||||
* @return {@code true} if the content of the first {@link InputStream} is equal
|
||||
* to the content of the second {@link InputStream}.
|
||||
*/
|
||||
public static boolean compare(InputStream input1, InputStream input2) throws IOException {
|
||||
if (!(input1 instanceof BufferedInputStream)) {
|
||||
input1 = new BufferedInputStream(input1);
|
||||
}
|
||||
if (!(input2 instanceof BufferedInputStream)) {
|
||||
input2 = new BufferedInputStream(input2);
|
||||
}
|
||||
int ch = input1.read();
|
||||
while (ch != NEGATIVE_ONE) {
|
||||
final int ch2 = input2.read();
|
||||
if (ch != ch2) {
|
||||
return false;
|
||||
}
|
||||
ch = input1.read();
|
||||
}
|
||||
final int ch2 = input2.read();
|
||||
return (ch2 == NEGATIVE_ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the content of two character streams ({@link Reader}s).
|
||||
*
|
||||
* @return {@code true} if the content of the first {@link Reader} is equal
|
||||
* to the content of the second {@link Reader}.
|
||||
*/
|
||||
public static boolean compare(Reader input1, Reader input2) throws IOException {
|
||||
if (!(input1 instanceof BufferedReader)) {
|
||||
input1 = new BufferedReader(input1);
|
||||
}
|
||||
if (!(input2 instanceof BufferedReader)) {
|
||||
input2 = new BufferedReader(input2);
|
||||
}
|
||||
|
||||
int ch = input1.read();
|
||||
while (ch != NEGATIVE_ONE) {
|
||||
final int ch2 = input2.read();
|
||||
if (ch != ch2) {
|
||||
return false;
|
||||
}
|
||||
ch = input1.read();
|
||||
}
|
||||
final int ch2 = input2.read();
|
||||
return (ch2 == NEGATIVE_ONE);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- defaults
|
||||
|
||||
/**
|
||||
* Returns default IO buffer size.
|
||||
*
|
||||
* @return default IO buffer size.
|
||||
*/
|
||||
private static int bufferSize() {
|
||||
return ioBufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns either count or default IO buffer size (whichever is smaller).
|
||||
*
|
||||
* @param count Number of characters or bytes to retrieve.
|
||||
* @return buffer size (either count or default IO buffer size, whichever is smaller).
|
||||
*/
|
||||
private static int bufferSize(final int count) {
|
||||
final int ioBufferSize = IOUtil.ioBufferSize;
|
||||
return Math.min(count, ioBufferSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns default encoding.
|
||||
*/
|
||||
private static Charset encoding() {
|
||||
return StandardCharsets.UTF_8;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- wrappers
|
||||
|
||||
/**
|
||||
* Returns new {@link CharArrayWriter} using default IO buffer size.
|
||||
*
|
||||
* @return new {@link CharArrayWriter} using default IO buffer size.
|
||||
*/
|
||||
private static CharArrayWriter createFastCharArrayWriter() {
|
||||
return new CharArrayWriter(bufferSize());
|
||||
}
|
||||
|
||||
private static ByteArrayOutputStream createFastByteArrayOutputStream() {
|
||||
return new ByteArrayOutputStream(bufferSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #inputStreamReadeOf(InputStream, Charset)
|
||||
*/
|
||||
public static InputStreamReader inputStreamReadeOf(final InputStream input) {
|
||||
return inputStreamReadeOf(input, encoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns new {@link InputStreamReader} using specified {@link InputStream} and encoding.
|
||||
*
|
||||
* @param input {@link InputStream}
|
||||
* @param encoding Encoding as {@link String} to use for {@link InputStreamReader}.
|
||||
* @return new {@link InputStreamReader}
|
||||
*/
|
||||
public static InputStreamReader inputStreamReadeOf(final InputStream input, final Charset encoding) {
|
||||
return new InputStreamReader(input, encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #outputStreamWriterOf(OutputStream, Charset)
|
||||
*/
|
||||
public static OutputStreamWriter outputStreamWriterOf(final OutputStream output) {
|
||||
return outputStreamWriterOf(output, encoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns new {@link OutputStreamWriter} using specified {@link OutputStream} and encoding.
|
||||
*
|
||||
* @param output {@link OutputStream}
|
||||
* @param encoding Encoding as {@link String} to use for {@link OutputStreamWriter}.
|
||||
* @return new {@link OutputStreamWriter}
|
||||
*/
|
||||
public static OutputStreamWriter outputStreamWriterOf(final OutputStream output, final Charset encoding) {
|
||||
return new OutputStreamWriter(output, encoding);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
package com.nebula.base.utils.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PushbackInputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2022/1/14 13:55
|
||||
* @description:
|
||||
*/
|
||||
public class UnicodeInputStream extends InputStream{
|
||||
|
||||
public static final int MAX_BOM_SIZE = 4;
|
||||
|
||||
private final PushbackInputStream internalInputStream;
|
||||
private boolean initialized;
|
||||
private int BOMSize = -1;
|
||||
private Charset encoding;
|
||||
private final Charset targetEncoding;
|
||||
|
||||
/**
|
||||
* Creates new unicode stream. It works in two modes: detect mode and read mode.
|
||||
* <p>
|
||||
* Detect mode is active when target encoding is not specified.
|
||||
* In detect mode, it tries to detect encoding from BOM if exist.
|
||||
* If BOM doesn't exist, encoding is not detected.
|
||||
* <p>
|
||||
* Read mode is active when target encoding is set. Then this stream reads
|
||||
* optional BOM for given encoding. If BOM doesn't exist, nothing is skipped.
|
||||
*/
|
||||
public UnicodeInputStream(final InputStream in, final Charset targetEncoding) {
|
||||
internalInputStream = new PushbackInputStream(in, MAX_BOM_SIZE);
|
||||
this.targetEncoding = targetEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns detected UTF encoding or {@code null} if no UTF encoding has been detected (i.e. no BOM).
|
||||
* If stream is not read yet, it will be {@link #init() initalized} first.
|
||||
*/
|
||||
public Charset getDetectedEncoding() {
|
||||
if (!initialized) {
|
||||
try {
|
||||
init();
|
||||
} catch (final IOException ioex) {
|
||||
throw new IllegalStateException(ioex);
|
||||
}
|
||||
}
|
||||
return encoding;
|
||||
}
|
||||
|
||||
public static final byte[] BOM_UTF32_BE = new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0xFE, (byte) 0xFF};
|
||||
public static final byte[] BOM_UTF32_LE = new byte[]{(byte) 0xFF, (byte) 0xFE, (byte) 0x00, (byte) 0x00};
|
||||
public static final byte[] BOM_UTF8 = new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};
|
||||
public static final byte[] BOM_UTF16_BE = new byte[]{(byte) 0xFE, (byte) 0xFF};
|
||||
public static final byte[] BOM_UTF16_LE = new byte[]{(byte) 0xFF, (byte) 0xFE};
|
||||
|
||||
/**
|
||||
* Detects and decodes encoding from BOM character.
|
||||
* Reads ahead four bytes and check for BOM marks.
|
||||
* Extra bytes are unread back to the stream, so only
|
||||
* BOM bytes are skipped.
|
||||
*/
|
||||
protected void init() throws IOException {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetEncoding == null) {
|
||||
|
||||
// DETECT MODE
|
||||
|
||||
final byte[] bom = new byte[MAX_BOM_SIZE];
|
||||
final int n = internalInputStream.read(bom, 0, bom.length);
|
||||
final int unread;
|
||||
|
||||
if ((bom[0] == BOM_UTF32_BE[0]) && (bom[1] == BOM_UTF32_BE[1]) && (bom[2] == BOM_UTF32_BE[2]) && (bom[3] == BOM_UTF32_BE[3])) {
|
||||
encoding = Charset.forName("UTF-32BE");
|
||||
unread = n - 4;
|
||||
} else if ((bom[0] == BOM_UTF32_LE[0]) && (bom[1] == BOM_UTF32_LE[1]) && (bom[2] == BOM_UTF32_LE[2]) && (bom[3] == BOM_UTF32_LE[3])) {
|
||||
encoding = Charset.forName("UTF-32LE");
|
||||
unread = n - 4;
|
||||
} else if ((bom[0] == BOM_UTF8[0]) && (bom[1] == BOM_UTF8[1]) && (bom[2] == BOM_UTF8[2])) {
|
||||
encoding = StandardCharsets.UTF_8;
|
||||
unread = n - 3;
|
||||
} else if ((bom[0] == BOM_UTF16_BE[0]) && (bom[1] == BOM_UTF16_BE[1])) {
|
||||
encoding = StandardCharsets.UTF_16BE;
|
||||
unread = n - 2;
|
||||
} else if ((bom[0] == BOM_UTF16_LE[0]) && (bom[1] == BOM_UTF16_LE[1])) {
|
||||
encoding = StandardCharsets.UTF_16LE;
|
||||
unread = n - 2;
|
||||
} else {
|
||||
// BOM not found, unread all bytes
|
||||
unread = n;
|
||||
}
|
||||
|
||||
BOMSize = MAX_BOM_SIZE - unread;
|
||||
|
||||
if (unread > 0) {
|
||||
internalInputStream.unread(bom, (n - unread), unread);
|
||||
}
|
||||
} else {
|
||||
|
||||
// READ MODE
|
||||
|
||||
byte[] bom = null;
|
||||
|
||||
final String targetEncodingName = targetEncoding.name();
|
||||
|
||||
switch (targetEncodingName) {
|
||||
case "UTF-8":
|
||||
bom = BOM_UTF8;
|
||||
break;
|
||||
case "UTF-16LE":
|
||||
bom = BOM_UTF16_LE;
|
||||
break;
|
||||
case "UTF-16BE":
|
||||
case "UTF-16":
|
||||
bom = BOM_UTF16_BE;
|
||||
break;
|
||||
case "UTF-32LE":
|
||||
bom = BOM_UTF32_LE;
|
||||
break;
|
||||
case "UTF-32BE":
|
||||
case "UTF-32":
|
||||
bom = BOM_UTF32_BE;
|
||||
break;
|
||||
default:
|
||||
// no UTF encoding, no BOM
|
||||
break;
|
||||
}
|
||||
|
||||
if (bom != null) {
|
||||
final byte[] fileBom = new byte[bom.length];
|
||||
final int n = internalInputStream.read(fileBom, 0, bom.length);
|
||||
|
||||
boolean bomDetected = true;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (fileBom[i] != bom[i]) {
|
||||
bomDetected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bomDetected) {
|
||||
internalInputStream.unread(fileBom, 0, fileBom.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes input stream. If stream was not used, encoding
|
||||
* will be unavailable.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
internalInputStream.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads byte from the stream.
|
||||
*/
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
init();
|
||||
return internalInputStream.read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns BOM size in bytes.
|
||||
* Returns <code>-1</code> if BOM not found.
|
||||
*/
|
||||
public int getBOMSize() {
|
||||
return BOMSize;
|
||||
}
|
||||
|
||||
}
|
|
@ -2,13 +2,14 @@ package com.nebula.web.boot.exception;
|
|||
|
||||
import com.nebula.web.boot.api.IResultCode;
|
||||
import com.nebula.web.boot.enums.ResultCode;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author : wh
|
||||
* @date : 2023/4/13 10:11
|
||||
* @description:
|
||||
*/
|
||||
public abstract class BaseException extends RuntimeException {
|
||||
@Getter public abstract class BaseException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
@ -34,8 +35,4 @@ public abstract class BaseException extends RuntimeException {
|
|||
this.code = code;
|
||||
}
|
||||
|
||||
public IResultCode getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
|||
* handler response value of all http api
|
||||
*/
|
||||
public class NebulaResponseBodyHandleReturnValue implements HandlerMethodReturnValueHandler, AsyncHandlerMethodReturnValueHandler {
|
||||
|
||||
private static final String ContentType = "application/json;charset=utf-8";
|
||||
/**
|
||||
* 处理所有非异常的错误
|
||||
*
|
||||
|
@ -36,7 +38,7 @@ public class NebulaResponseBodyHandleReturnValue implements HandlerMethodReturnV
|
|||
mavContainer.setRequestHandled(true);
|
||||
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
|
||||
assert response != null;
|
||||
response.setContentType("application/json;charset=utf-8");
|
||||
response.setContentType(ContentType);
|
||||
NebulaResponse<Object> baseResponse = new NebulaResponse<>();
|
||||
baseResponse.setCode(ResultCode.SUCCESS.getCode());
|
||||
baseResponse.setMsg(ResultCode.SUCCESS.getMessage());
|
||||
|
|
Loading…
Reference in New Issue