add utils

This commit is contained in:
weihu 2023-12-08 10:56:54 +08:00
parent 6e09a9bd6c
commit 2feb8827fe
24 changed files with 9503 additions and 13 deletions

View File

@ -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)

View File

@ -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

View File

@ -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'};
}

View File

@ -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();
}
}
}

View File

@ -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

View File

@ -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[]) {

View File

@ -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));
}
}

View 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();
}
}

View File

@ -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 + "$";
}
}

View File

@ -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;
}
}

View File

@ -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 = "..";
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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());