소스 검색

commit e1c5ed006593dbdbbdbc64db6c9d73c1c3526319 (HEAD -> master, origin/master, origin/HEAD)
Author: reghao <reghaodev@gmail.com>
Date: Mon Jan 20 10:55:16 2025 +0800

dateTimePattern 格式修改为 "yyyy-MM-dd HH:mm:ss.SSS" 包含毫秒

commit a8eb980933c80f1020deb1f72435dc3220a3207a
Author: reghao <reghaodev@gmail.com>
Date: Thu Nov 21 09:11:08 2024 +0800

RsaCryptor 添加读写密钥对到本地文件系统的方法

commit 7d86ab0506fe72f012f15acf246534a6de220f03
Author: reghao <reghaodev@gmail.com>
Date: Wed Nov 20 16:30:03 2024 +0800

WebResult 放到 web 模块中, 因为包含 http 相关的 x-request-id

commit b2a48c72c00c40b0ddb24865d5500d0545213a5f
Author: reghao <reghaodev@gmail.com>
Date: Fri Nov 15 16:45:39 2024 +0800

RsaCryptor 中添加 pubkey 和 prikey pem 文件的生成和 pem 文件的加载

commit c3616d8aa52f5475d0c87abe4a433b654437f30b
Author: reghao <reghaodev@gmail.com>
Date: Fri Nov 8 22:37:15 2024 +0800

TextFile 中使用 RandomAccessFile 实现 append 方法

commit ed4748583f752ebade11d5caa3f53621c7d11527
Author: reghao <reghaodev@gmail.com>
Date: Fri Oct 25 21:47:05 2024 +0800

update FileSplitter

commit 490cd2f4243287ad252314a44823ff4f92a9db7d
Author: reghao <reghaodev@gmail.com>
Date: Thu Oct 24 16:57:02 2024 +0800

FilePart 名字修改为 FileSplitter

commit d6a8ed1dc88b60e7171a99fc975f902d389e700e
Author: reghao <reghaodev@gmail.com>
Date: Mon Oct 21 14:59:53 2024 +0800

删除 cn.reghao.jutil.jdk.store

commit 330deda5252cc5ea67880970a47b4cf55ac4ee86
Author: reghao <reghaodev@gmail.com>
Date: Tue Aug 27 16:35:00 2024 +0800

PageList.pageList 添加一个以 cn.reghao.jutil.jdk.db.Page 作为参数的方法

commit 1b90cc59ee6e28b9de6dffd65451d5c2b96ee85e
Author: reghao <reghaodev@gmail.com>
Date: Tue Aug 20 15:09:02 2024 +0800

修改 IdGenerator#nextId 方法中 nextId 的生成方法, 避免出现 number cannot be greater than 9007199254740992L 异常

commit 25fc6b8eabe9e50cc00256220e5c53d82f510eb5
Author: reghao <reghaodev@gmail.com>
Date: Thu Aug 15 22:24:40 2024 +0800

以 jutil1 仓库 master 分支的 4fa2ff7f3a 版本为起点

reghao 1 년 전
부모
커밋
adacadaccc

+ 1 - 1
jdk/src/main/java/cn/reghao/jutil/jdk/converter/DateTimeConverter.java

@@ -14,7 +14,7 @@ import java.util.Locale;
  * @date 2020-03-20 10:20:01
  */
 public class DateTimeConverter {
-    private final static String dateTimePattern = "yyyy-MM-dd HH:mm:ss";
+    private final static String dateTimePattern = "yyyy-MM-dd HH:mm:ss.SSS";
 
     /**
      * 将 LocalDateTime 对象格式化为 yyyy-MM-dd HH:mm:ss 格式的字符串

+ 4 - 0
jdk/src/main/java/cn/reghao/jutil/jdk/db/PageList.java

@@ -38,6 +38,10 @@ public class PageList<T> implements Serializable {
         return new PageList<>(pageNumber, pageSize, total, list);
     }
 
+    public static <T> PageList<T> pageList(Page page, int total, List<T> list) {
+        return new PageList<>(page.getPage(), page.getSize(), total, list);
+    }
+
     public static <T> PageList<T> pageList(int pageNumber, int pageSize, int total, String lastId, List<T> list) {
         return new PageList<>(pageNumber, pageSize, total, lastId, list);
     }

+ 5 - 5
jdk/src/main/java/cn/reghao/jutil/jdk/io/FilePart.java → jdk/src/main/java/cn/reghao/jutil/jdk/io/FileSplitter.java

@@ -11,15 +11,15 @@ import java.util.Objects;
  * @author reghao
  * @date 2023-03-24 10:32:58
  */
-public class FilePart {
+public class FileSplitter {
     private final int partSize;
 
-    public FilePart() {
+    public FileSplitter() {
         // 10MiB
         this.partSize = 10*1024*1024;
     }
 
-    public FilePart(int len) {
+    public FileSplitter(int len) {
         this.partSize = len*1024*1024;
     }
 
@@ -38,7 +38,7 @@ public class FilePart {
 
         for (int i = 0; i < total; i++) {
             long start = (long) i*partSize;
-            byte[] part = getPart(file.getAbsolutePath(), partSize, start);
+            byte[] part = getPart(file.getAbsolutePath(), start);
             if (part.length == 0) {
                 break;
             }
@@ -56,7 +56,7 @@ public class FilePart {
         }
     }
 
-    public byte[] getPart(String absolutePath, int partSize, long start) throws IOException {
+    public byte[] getPart(String absolutePath, long start) throws IOException {
         RandomAccessFile raf = new RandomAccessFile(absolutePath, "r");
         raf.seek(start);
 

+ 1 - 0
jdk/src/main/java/cn/reghao/jutil/jdk/result/WebResult.java

@@ -10,6 +10,7 @@ import java.util.UUID;
  * @author reghao
  * @date 2022-01-07 14:05:35
  */
+@Deprecated
 public class WebResult<T> {
     private final int code;
     private final String msg;

+ 93 - 0
jdk/src/main/java/cn/reghao/jutil/jdk/security/RsaCryptor.java

@@ -1,11 +1,15 @@
 package cn.reghao.jutil.jdk.security;
 
+import cn.reghao.jutil.jdk.text.TextFile;
+
 import javax.crypto.Cipher;
+import java.io.File;
 import java.nio.charset.StandardCharsets;
 import java.security.*;
 import java.security.interfaces.RSAPrivateKey;
 import java.security.interfaces.RSAPublicKey;
 import java.security.spec.EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.Base64;
@@ -42,6 +46,95 @@ public class RsaCryptor {
         return keyMap;
     }
 
+    public static Map<String, Object> getRsaPair(String baseDir) throws NoSuchAlgorithmException {
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
+        keyPairGenerator.initialize(KEY_LENGTH, new SecureRandom());
+        KeyPair keyPair = keyPairGenerator.generateKeyPair();
+        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
+        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
+
+        String privateKeyStr = new String(encoder.encode(privateKey.getEncoded()));
+        String privateKeyPath = String.format("%s/private.pem", baseDir);
+        savePemFile(privateKeyStr, privateKeyPath);
+
+        String publicKeyStr = new String(encoder.encode(publicKey.getEncoded()));
+        String publicKeyPath = String.format("%s/public.pem", baseDir);
+        savePemFile(publicKeyStr, publicKeyPath);
+
+        Map<String, Object> keyMap = new HashMap<>();
+        keyMap.put("privateKey", privateKey);
+        keyMap.put("publicKey", publicKey);
+        return keyMap;
+    }
+
+    private static void savePemFile(String keyStr, String filePath) {
+        try {
+            textFile.write(new File(filePath), keyStr);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    static TextFile textFile = new TextFile();
+    public static Map<String, Object> loadRsaPair(String baseDir) throws NoSuchAlgorithmException, InvalidKeySpecException {
+        String publicKeyPath = String.format("%s/public.pem", baseDir);
+        String publicKeyStr = textFile.readFile(publicKeyPath);
+        byte[] decoded = decoder.decode(publicKeyStr.getBytes(StandardCharsets.UTF_8));
+        EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(decoded);
+        RSAPublicKey rsaPublicKey = (RSAPublicKey) KeyFactory.getInstance(ALGORITHM).generatePublic(encodedKeySpec);
+
+        String privateKeyPath = String.format("%s/private.pem", baseDir);
+        String privateKeyStr = textFile.readFile(privateKeyPath);
+        byte[] decoded1 = decoder.decode(privateKeyStr.getBytes(StandardCharsets.UTF_8));
+        EncodedKeySpec encodedKeySpec1 = new PKCS8EncodedKeySpec(decoded1);
+        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) KeyFactory.getInstance(ALGORITHM).generatePrivate(encodedKeySpec1);
+
+        Map<String, Object> keyMap = new HashMap<>();
+        keyMap.put("privateKey", rsaPrivateKey);
+        keyMap.put("publicKey", rsaPublicKey);
+        return keyMap;
+    }
+
+    public static RSAPublicKey getRSAPublicKey(File pemFile) {
+        String publicKeyStr = textFile.readFile(pemFile.getAbsolutePath());
+        return getRSAPublicKey(publicKeyStr);
+    }
+
+    public static RSAPublicKey getRSAPublicKey(String publicKeyStr) {
+        byte[] decoded = decoder.decode(publicKeyStr.getBytes(StandardCharsets.UTF_8));
+        EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(decoded);
+        try {
+            RSAPublicKey rsaPublicKey = (RSAPublicKey) KeyFactory.getInstance(ALGORITHM).generatePublic(encodedKeySpec);
+            return rsaPublicKey;
+        } catch (InvalidKeySpecException e) {
+            e.printStackTrace();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+    public static RSAPrivateKey getRSAPrivateKey(File pemFile) {
+        String privateKeyStr = textFile.readFile(pemFile.getAbsolutePath());
+        return getRSAPrivateKey(privateKeyStr);
+    }
+
+    public static RSAPrivateKey getRSAPrivateKey(String privateKeyStr) {
+        byte[] decoded1 = decoder.decode(privateKeyStr.getBytes(StandardCharsets.UTF_8));
+        EncodedKeySpec encodedKeySpec1 = new PKCS8EncodedKeySpec(decoded1);
+        try {
+            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) KeyFactory.getInstance(ALGORITHM).generatePrivate(encodedKeySpec1);
+            return rsaPrivateKey;
+        } catch (InvalidKeySpecException e) {
+            e.printStackTrace();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
     public static String encrypt(String pText, String publicKey) throws Exception {
         byte[] decoded = decoder.decode(publicKey.getBytes(StandardCharsets.UTF_8));
         EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(decoded);

+ 0 - 17
jdk/src/main/java/cn/reghao/jutil/jdk/store/LoadBalancer.java

@@ -1,17 +0,0 @@
-package cn.reghao.jutil.jdk.store;
-
-import java.util.Comparator;
-import java.util.List;
-
-/**
- * @author reghao
- * @date 2022-03-22 13:53:08
- */
-public class LoadBalancer {
-    public StoreDir getStoreDir(long fileSize) {
-        LocalStore localStore = LocalStores.getMaxStore(fileSize);
-        List<StoreDir> subDirs = LocalStores.getSubDirs(localStore.getDiskDir());
-        subDirs.sort(Comparator.comparingInt(StoreDir::getTotal));
-        return subDirs.get(0);
-    }
-}

+ 0 - 72
jdk/src/main/java/cn/reghao/jutil/jdk/store/LocalStore.java

@@ -1,72 +0,0 @@
-package cn.reghao.jutil.jdk.store;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * 表示一块磁盘
- *
- * @author reghao
- * @date 2022-05-23 15:00:59
- */
-public class LocalStore {
-    private final String logicalDisk;
-    // disk mounted directory
-    private final String diskDir;
-    private final long total;
-    private final AtomicLong available;
-    private final long max;
-
-    public LocalStore(String logicalDisk, String diskDir, long total, long available, double maxPercent) {
-        this.logicalDisk = logicalDisk;
-        this.diskDir = diskDir;
-        this.total = total;
-        this.available = new AtomicLong(available);
-        BigDecimal bigDecimal1 = new BigDecimal(total*10);
-        BigDecimal bigDecimal2 = new BigDecimal(maxPercent*10);
-        BigDecimal result = bigDecimal1.divide(bigDecimal2, RoundingMode.DOWN);
-        this.max = result.longValue();
-    }
-
-    public String getLogicalDisk() {
-        return logicalDisk;
-    }
-
-    public String getDiskDir() {
-        return diskDir;
-    }
-
-    public long getTotal() {
-        return total;
-    }
-
-    public long getAvailable() {
-        return available.get();
-    }
-
-    public void setCurrentAvailable(long currentAvailable) {
-        available.getAndSet(currentAvailable);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = 17;
-        result = result * 31 + diskDir.hashCode();
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object other) {
-        if (other == this) {
-            return true;
-        }
-
-        if (other instanceof LocalStore) {
-            LocalStore o = (LocalStore) other;
-            return o.diskDir.equals(diskDir);
-        } else {
-            return false;
-        }
-    }
-}

+ 0 - 97
jdk/src/main/java/cn/reghao/jutil/jdk/store/LocalStores.java

@@ -1,97 +0,0 @@
-package cn.reghao.jutil.jdk.store;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.FileStore;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.*;
-
-/**
- * @author reghao
- * @date 2022-05-23 18:21:22
- */
-public class LocalStores {
-    private static final Map<String, LocalStore> storeMap = new HashMap<>();
-    private static final Map<String, Map<String, StoreDir>> storeDirMap = new HashMap<>();
-
-    public static void init(List<String> diskDirs) throws IOException {
-        Map<String, String> map = new HashMap<>();
-        for (String diskDir : diskDirs) {
-            FileStore fileStore = Files.getFileStore(Path.of(diskDir));
-            String logicalDisk = fileStore.name();
-            String prevValue = map.putIfAbsent(logicalDisk, diskDir);
-            if (prevValue == null) {
-                long total = fileStore.getTotalSpace();
-                long available = fileStore.getUsableSpace();
-                LocalStore localStore = new LocalStore(logicalDisk, diskDir, total, available, 0.9);
-                storeMap.put(diskDir, localStore);
-                storeDirMap.computeIfAbsent(diskDir, k -> new HashMap<>());
-                createSubDirs(diskDir);
-            } else {
-                String msg = String.format("%s's mounted directory %s has already associated with %s", logicalDisk, diskDir, prevValue);
-                System.out.println(msg);
-            }
-        }
-    }
-
-    private static void createSubDirs(String diskDir) throws IOException {
-        int total = 128;
-        for (int i = 0; i < total; i++) {
-            for (int j = 0; j < total; j++) {
-                String baseDir = String.format("%s/%s/%s/", diskDir, i, j);
-                File dir = new File(baseDir);
-                if (!dir.exists() && !dir.mkdirs()) {
-                    String msg = String.format("create %s failed", dir);
-                    throw new IOException(msg);
-                }
-
-                storeDirMap.get(diskDir).put(baseDir, new StoreDir(baseDir));
-            }
-        }
-    }
-
-    public static void initStoreDirs(String diskDir, Map<String, Integer> map) {
-        Map<String, StoreDir> map1 = storeDirMap.get(diskDir);
-        if (map1 == null) {
-            return;
-        }
-
-        map.forEach((path, total) -> {
-            StoreDir storeDir = map1.get(path);
-            if (storeDir != null) {
-                storeDir.setTotal(total);
-            }
-        });
-    }
-
-    // TODO 优化算法, 处理异常
-    public static LocalStore getMaxStore(long size) {
-        Map<String, Long> map = new HashMap<>();
-        for (Map.Entry<String, LocalStore> entry : storeMap.entrySet()) {
-            String diskDir = entry.getKey();
-            LocalStore localStore = entry.getValue();
-            long currentAvailable = localStore.getAvailable() - size;
-            map.put(diskDir, currentAvailable);
-        }
-
-        List<String> diskDirs = new ArrayList<>();
-        // diskDirs 中的元素升序排列
-        map.entrySet().stream()
-                .sorted(Map.Entry.comparingByValue())
-                .forEachOrdered(b -> diskDirs.add(b.getKey()));
-
-        String maxDisk = diskDirs.get(diskDirs.size()-1);
-        LocalStore localStore = storeMap.get(maxDisk);
-        localStore.setCurrentAvailable(map.get(maxDisk));
-        return localStore;
-    }
-    
-    public static List<StoreDir> getSubDirs(String diskDir) {
-        return new ArrayList<>(storeDirMap.get(diskDir).values());
-    }
-
-    public static List<LocalStore> getLocalStores() {
-        return new ArrayList<>(storeMap.values());
-    }
-}

+ 0 - 37
jdk/src/main/java/cn/reghao/jutil/jdk/store/StoreDir.java

@@ -1,37 +0,0 @@
-package cn.reghao.jutil.jdk.store;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * @author reghao
- * @date 2022-05-23 23:31:21
- */
-public class StoreDir {
-    private final String baseDir;
-    private final AtomicInteger total;
-
-    public StoreDir(String baseDir) {
-        this.baseDir = baseDir;
-        this.total = new AtomicInteger(0);
-    }
-
-    public String getBaseDir() {
-        return baseDir;
-    }
-
-    public void setTotal(int total) {
-        this.total.setPlain(total);
-    }
-
-    public int getTotal() {
-        return total.get();
-    }
-
-    public void incr() {
-        this.total.incrementAndGet();
-    }
-
-    public void decr() {
-        this.total.decrementAndGet();
-    }
-}

+ 0 - 26
jdk/src/main/java/cn/reghao/jutil/jdk/store/SubDirCount.java

@@ -1,26 +0,0 @@
-package cn.reghao.jutil.jdk.store;
-
-/**
- * @author reghao
- * @date 2023-11-01 21:38:59
- */
-public class SubDirCount {
-    private String relativeDir;
-    private int total;
-
-    public void setRelativeDir(String relativeDir) {
-        this.relativeDir = relativeDir;
-    }
-
-    public String getRelativeDir() {
-        return relativeDir;
-    }
-
-    public void setTotal(int total) {
-        this.total = total;
-    }
-
-    public int getTotal() {
-        return total;
-    }
-}

+ 13 - 5
jdk/src/main/java/cn/reghao/jutil/jdk/text/TextFile.java

@@ -222,11 +222,19 @@ public class TextFile {
     }
 
     public void append(String filePath, List<String> lines) throws IOException {
-        int bufSize = 8*1024*1024;
-        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath)), bufSize);
-        for (String line : lines) {
-            out.append(line);
+        File file = new File(filePath);
+        RandomAccessFile raf = new RandomAccessFile(file, "rw");
+        String line = raf.readLine();
+        while (line != null) {
+            line = raf.readLine();
         }
-        out.close();
+
+        for (String str : lines) {
+            String str1 = str + System.lineSeparator();
+            // 调用 writeChars 方法会出现多余的空格,因为这个方法以 2 字节为基准
+            raf.write(str1.getBytes());
+        }
+
+        raf.close();
     }
 }

+ 4 - 1
tool/src/main/java/cn/reghao/jutil/tool/id/IdGenerator.java

@@ -2,6 +2,8 @@ package cn.reghao.jutil.tool.id;
 
 import org.hashids.Hashids;
 
+import java.util.concurrent.ThreadLocalRandom;
+
 /**
  * @author reghao
  * @date 2021-11-22 14:05:13
@@ -34,7 +36,8 @@ public class IdGenerator {
      * @date 2021-12-24 上午11:30
      */
     public String stringId() {
-        long nextId = snowFlake.nextId();
+        //long nextId = snowFlake.nextId();
+        long nextId = ThreadLocalRandom.current().nextLong(Hashids.MAX_NUMBER);
         return hashids.encode(nextId);
     }
 }

+ 103 - 0
web/src/main/java/cn/reghao/jutil/web/WebResult.java

@@ -0,0 +1,103 @@
+package cn.reghao.jutil.web;
+
+import cn.reghao.jutil.jdk.result.Result;
+import cn.reghao.jutil.jdk.result.ResultStatus;
+import cn.reghao.jutil.jdk.serializer.JsonConverter;
+
+/**
+ * HTTP 响应 body 数据
+ *
+ * @author reghao
+ * @date 2022-01-07 14:05:35
+ */
+public class WebResult<T> {
+    private final int code;
+    private final String msg;
+    private final long timestamp;
+    private final String requestId;
+    private T data;
+
+    private WebResult(Integer code, String msg) {
+        this.code = code;
+        this.msg = msg;
+        this.timestamp = System.currentTimeMillis();
+        this.requestId = ServletUtil.getHeader("x-request-id");
+    }
+
+    private WebResult(ResultStatus resultStatus) {
+        this.code = resultStatus.getCode();
+        this.msg = resultStatus.getMsg();
+        this.timestamp = System.currentTimeMillis();
+        this.requestId = ServletUtil.getHeader("x-request-id");
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    public String getRequestId() {
+        return requestId;
+    }
+
+    private void setData(T data) {
+        this.data = data;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public static <T> String result(Result result) {
+        WebResult<T> webBody = new WebResult<>(result.getCode(), result.getMsg());
+        return JsonConverter.objectToJson(webBody);
+    }
+
+    public static <T> String success() {
+        WebResult<T> webBody = new WebResult<>(ResultStatus.SUCCESS.getCode(), ResultStatus.SUCCESS.getMsg());
+        return JsonConverter.objectToJson(webBody);
+    }
+
+    public static <T> String successWithMsg(String msg) {
+        WebResult<T> webBody = new WebResult<>(ResultStatus.SUCCESS.getCode(), msg);
+        return JsonConverter.objectToJson(webBody);
+    }
+
+    public static <T> String success(T data) {
+        WebResult<T> webBody = new WebResult<>(ResultStatus.SUCCESS.getCode(), ResultStatus.SUCCESS.getMsg());
+        webBody.setData(data);
+        return JsonConverter.objectToJson(webBody);
+    }
+
+    public static <T> String fail() {
+        WebResult<T> webBody = new WebResult<>(ResultStatus.FAIL.getCode(), ResultStatus.FAIL.getMsg());
+        return JsonConverter.objectToJson(webBody);
+    }
+
+    public static <T> String failWithMsg(String msg) {
+        WebResult<T> webBody = new WebResult<>(ResultStatus.FAIL.getCode(), msg);
+        return JsonConverter.objectToJson(webBody);
+    }
+
+    public static <T> String notFound() {
+        WebResult<T> webBody = new WebResult<>(ResultStatus.NOTFOUND);
+        return JsonConverter.objectToJson(webBody);
+    }
+
+    public static <T> String error() {
+        WebResult<T> webBody = new WebResult<>(ResultStatus.ERROR.getCode(), ResultStatus.ERROR.getMsg());
+        return JsonConverter.objectToJson(webBody);
+    }
+
+    public static <T> String errorWithMsg(String msg) {
+        WebResult<T> webBody = new WebResult<>(ResultStatus.ERROR.getCode(), msg);
+        return JsonConverter.objectToJson(webBody);
+    }
+}