Forráskód Böngészése

Merge branch 'release'

# Conflicts:
#	README.en.md
#	README.md
#	class-winter-core/dependency-reduced-pom.xml
#	class-winter-core/pom.xml
#	class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/AllTest.java
#	class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/AlreadyProtectedLibs_Test.java
#	class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/Debug_Test.java
#	class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/ExcludePrefix_Test.java
#	class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/FinalName_Test.java
#	class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/IncludeLibs_Test.java
#	class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/IncludePrefix_Test.java
#	class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/OriginJarOrWar_Test.java
#	class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/Password_Test.java
#	class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/SupportFile_Test.java
#	class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/Tips_Test.java
#	class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/War_Test.java
#	class-winter-maven-plugin/pom.xml
#	pom.xml
JustryDeng 4 éve
szülő
commit
3545200e4d
25 módosított fájl, 312 hozzáadás és 166 törlés
  1. 2 2
      README.en.md
  2. 2 2
      README.md
  3. 1 1
      class-winter-core/dependency-reduced-pom.xml
  4. 1 1
      class-winter-core/pom.xml
  5. 7 2
      class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/executor/EncryptExecutor.java
  6. 38 0
      class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/FileOrderSupport.java
  7. 42 6
      class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/JarUtil.java
  8. 2 2
      class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/JavassistUtil.java
  9. 0 125
      class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/RsaUtil.java
  10. 31 0
      class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/SimpleFileOrderSupport.java
  11. 1 1
      class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/AllTest.java
  12. 2 2
      class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/AlreadyProtectedLibs_Test.java
  13. 2 2
      class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/Debug_Test.java
  14. 2 2
      class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/ExcludePrefix_Test.java
  15. 1 1
      class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/FinalName_Test.java
  16. 1 1
      class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/IncludeLibs_Test.java
  17. 1 1
      class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/IncludePrefix_Test.java
  18. 2 2
      class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/OriginJarOrWar_Test.java
  19. 1 1
      class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/Password_Test.java
  20. 2 2
      class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/SupportFile_Test.java
  21. 3 3
      class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/Tips_Test.java
  22. 5 5
      class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/War_Test.java
  23. BIN
      class-winter-core/src/test/resources/class-winter-core-2.0.0.jar
  24. 1 1
      class-winter-maven-plugin/pom.xml
  25. 162 1
      pom.xml

+ 2 - 2
README.en.md

@@ -1,6 +1,6 @@
 ### <font face="幼圆"  color = "#F53B45">**郑重声明**</font>
 
-&emsp;&emsp;class-winter是本人在学习完[**class-final(v1.1.9)**](https://gitee.com/roseboy/classfinal)后,仿照class-final进行编写的,整体思路与class-final一致,代码部分(约20%~30%)复用了class-final中的代码。可将class-winter看作是class-final的一个分支。
+&emsp;&emsp;class-winter是本人在学习完[**class-final(v1.1.9)**](https://gitee.com/roseboy/classfinal) 后,仿照class-final进行编写的,整体思路与class-final一致,代码部分(约20%~30%)复用了class-final中的代码。可将class-winter看作是class-final的一个分支。
 
 ### <font  face="幼圆" color = "#3399EA" >功能与特性</font>
 - 支持war加密。
@@ -42,7 +42,7 @@
   ```
   注:不必担心信息泄漏问题,使用此方式生成混淆的jar包时,会擦除pom.xml中关于class-winter-plugin的信息。
 
-- #### <font face="幼圆" ><font face="幼圆"  color = "#86CA5E">**方式二**</font>:通过[**class-winter-core.jar**](https://gitee.com/JustryDeng/class-winter/raw/master/class-winter-core/src/test/resources/class-winter-core-1.2.3.jar)主动加密。</font>
+- #### <font face="幼圆" ><font face="幼圆"  color = "#86CA5E">**方式二**</font>:通过[**class-winter-core.jar**](https://gitee.com/JustryDeng/class-winter/raw/master/class-winter-core/src/test/resources/class-winter-core-2.0.0.jar) 主动加密。</font>
 
   ```bash
   java -jar class-winter-core-${version}.jar originJarOrWar=${要加密的项目.jar或.war包} includePrefix=${加密范围} [k3=v3 k4=v4 ...]

+ 2 - 2
README.md

@@ -1,6 +1,6 @@
 ### <font face="幼圆"  color = "#F53B45">**郑重声明**</font>
 
-&emsp;&emsp;class-winter是本人在学习完[**class-final(v1.1.9)**](https://gitee.com/roseboy/classfinal)后,仿照class-final进行编写的,整体思路与class-final一致,代码部分(约20%~30%)复用了class-final中的代码。可将class-winter看作是class-final的一个分支。
+&emsp;&emsp;class-winter是本人在学习完[**class-final(v1.1.9)**](https://gitee.com/roseboy/classfinal) 后,仿照class-final进行编写的,整体思路与class-final一致,代码部分(约20%~30%)复用了class-final中的代码。可将class-winter看作是class-final的一个分支。
 
 ### <font  face="幼圆" color = "#3399EA" >功能与特性</font>
 - 支持war加密。
@@ -42,7 +42,7 @@
   ```
   注:不必担心信息泄漏问题,使用此方式生成混淆的jar包时,会擦除pom.xml中关于class-winter-plugin的信息。
 
-- #### <font face="幼圆" ><font face="幼圆"  color = "#86CA5E">**方式二**</font>:通过[**class-winter-core.jar**](https://gitee.com/JustryDeng/class-winter/raw/master/class-winter-core/src/test/resources/class-winter-core-1.2.3.jar)主动加密。</font>
+- #### <font face="幼圆" ><font face="幼圆"  color = "#86CA5E">**方式二**</font>:通过[**class-winter-core.jar**](https://gitee.com/JustryDeng/class-winter/raw/master/class-winter-core/src/test/resources/class-winter-core-2.0.0.jar) 主动加密。</font>
 
   ```bash
   java -jar class-winter-core-${version}.jar originJarOrWar=${要加密的项目.jar或.war包} includePrefix=${加密范围} [k3=v3 k4=v4 ...]

+ 1 - 1
class-winter-core/dependency-reduced-pom.xml

@@ -3,7 +3,7 @@
   <parent>
     <artifactId>class-winter</artifactId>
     <groupId>com.idea-aedi</groupId>
-    <version>1.2.3</version>
+    <version>2.0.0</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>class-winter-core</artifactId>

+ 1 - 1
class-winter-core/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <groupId>com.idea-aedi</groupId>
         <artifactId>class-winter</artifactId>
-        <version>1.2.3</version>
+        <version>2.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 7 - 2
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/executor/EncryptExecutor.java

@@ -14,6 +14,7 @@ import winter.com.ideaaedi.classwinter.util.Cache;
 import winter.com.ideaaedi.classwinter.util.Constant;
 import winter.com.ideaaedi.classwinter.util.EncryptUtil;
 import winter.com.ideaaedi.classwinter.util.ExceptionUtil;
+import winter.com.ideaaedi.classwinter.util.FileOrderSupport;
 import winter.com.ideaaedi.classwinter.util.IOUtil;
 import winter.com.ideaaedi.classwinter.util.JarUtil;
 import winter.com.ideaaedi.classwinter.util.JavaagentCmdArgs;
@@ -21,6 +22,7 @@ import winter.com.ideaaedi.classwinter.util.JavassistUtil;
 import winter.com.ideaaedi.classwinter.util.Logger;
 import winter.com.ideaaedi.classwinter.util.Pair;
 import winter.com.ideaaedi.classwinter.util.PathUtil;
+import winter.com.ideaaedi.classwinter.util.SimpleFileOrderSupport;
 import winter.com.ideaaedi.classwinter.util.StrUtil;
 
 import java.io.File;
@@ -61,6 +63,7 @@ public class EncryptExecutor {
         CLASS_WINTER_FILES.add(Constant.class.getName().replace(".", "/") + Constant.CLASS_SUFFIX);
         CLASS_WINTER_FILES.add(EncryptUtil.class.getName().replace(".", "/") + Constant.CLASS_SUFFIX);
         CLASS_WINTER_FILES.add(ExceptionUtil.class.getName().replace(".", "/") + Constant.CLASS_SUFFIX);
+        CLASS_WINTER_FILES.add(FileOrderSupport.class.getName().replace(".", "/") + Constant.CLASS_SUFFIX);
         CLASS_WINTER_FILES.add(IOUtil.class.getName().replace(".", "/") + Constant.CLASS_SUFFIX);
         CLASS_WINTER_FILES.add(JarUtil.class.getName().replace(".", "/") + Constant.CLASS_SUFFIX);
         CLASS_WINTER_FILES.add(JavaagentCmdArgs.class.getName().replace(".", "/") + Constant.CLASS_SUFFIX);
@@ -68,6 +71,7 @@ public class EncryptExecutor {
         CLASS_WINTER_FILES.add(Logger.class.getName().replace(".", "/") + Constant.CLASS_SUFFIX);
         CLASS_WINTER_FILES.add(Pair.class.getName().replace(".", "/") + Constant.CLASS_SUFFIX);
         CLASS_WINTER_FILES.add(PathUtil.class.getName().replace(".", "/") + Constant.CLASS_SUFFIX);
+        CLASS_WINTER_FILES.add(SimpleFileOrderSupport.class.getName().replace(".", "/") + Constant.CLASS_SUFFIX);
         CLASS_WINTER_FILES.add(StrUtil.class.getName().replace(".", "/") + Constant.CLASS_SUFFIX);
         CLASS_WINTER_FILES.add(Reverses.class.getName().replace(".", "/") + Constant.CLASS_SUFFIX);
         CLASS_WINTER_FILES.add(Reverses.class.getName().replace(".", "/").replace("Reverses", "Reverses$1") + Constant.CLASS_SUFFIX);
@@ -195,7 +199,7 @@ public class EncryptExecutor {
         Logger.debug(EncryptExecutor.class, "Generate seal -> " + Constant.SEAL);
         
         // step0. 解压jar到jarRootDir下
-        JarUtil.unJarWar(originJarOrWar, targetRootDir);
+        List<String> filePathList = JarUtil.unJarWar(originJarOrWar, targetRootDir);
         showProcess("step00", "step11", "un-jar-war");
         
         // step1. jar中的某些lib可能也需要加密,这里先(将那些需要加密的lib)进行解压,(解压到对应的临时目录,以便后面进行加密处理)
@@ -241,7 +245,7 @@ public class EncryptExecutor {
         
         // step10. 压缩targetRootDir目录为绝对文件路径名为generatedJarWar的jar(or war)包
         String generatedJarWar = generateJarWarPath(this.originIsJar);
-        JarUtil.doJarWar(targetRootDir, generatedJarWar);
+        JarUtil.doJarWar(targetRootDir, generatedJarWar, new SimpleFileOrderSupport(filePathList));
         showProcess("step10", "step11", "generate-jar-war-path");
         
         // step11. 删除临时目录
@@ -502,6 +506,7 @@ public class EncryptExecutor {
             return;
         }
         libJarAndTmpDirMap.forEach((jarFilePath, tmpDirPath) -> {
+            // lib下的jar都不是spring-boot jar,都是些普通jar,不需要排序,即:不需要使用三个参数的方法
             JarUtil.doJarWar(tmpDirPath, jarFilePath);
             // 删除临时目录
             IOUtil.delete(new File(tmpDirPath));

+ 38 - 0
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/FileOrderSupport.java

@@ -0,0 +1,38 @@
+package winter.com.ideaaedi.classwinter.util;
+
+import java.io.File;
+import java.util.Objects;
+
+/**
+ * 文件排序支持
+ *
+ * @author JustryDeng
+ * @since 2021/11/7 17:15:23
+ */
+public interface FileOrderSupport {
+    
+    /** 默认的排序序号 */
+    int DEFAULT_FILE_ORDER = Integer.MAX_VALUE;
+    
+    /**
+     * 获取文件的排序序号
+     *
+     * @param file
+     *            文件
+     * @return  文件的排序序号
+     */
+    default int obtainFileOrder(File file) {
+        Objects.requireNonNull(file, "file cannot be null.");
+        Integer order = fileOrder(file);
+        return order == null ? DEFAULT_FILE_ORDER : order;
+    }
+    
+    /**
+     * 获取文件的排序序号
+     *
+     * @param file
+     *            文件
+     * @return  文件的排序序号
+     */
+    Integer fileOrder(File file);
+}

+ 42 - 6
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/JarUtil.java

@@ -11,11 +11,16 @@ import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.attribute.FileTime;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
+import java.util.stream.Collectors;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
@@ -31,6 +36,13 @@ public final class JarUtil {
     /** 打包时需要忽略的(可能由操作系统产生的)文件 */
     private static final String[] IGNORE_FILE_SUFFIX = {".DS_Store", "Thumbs.db"};
     
+    /**
+     * @see JarUtil#doJarWar(String, String, FileOrderSupport)
+     */
+    public static String doJarWar(String srcDir, String targetJarOrWar) {
+        return doJarWar(srcDir, targetJarOrWar, null);
+    }
+    
     /**
      * 把目录压缩成jar(or war)
      *
@@ -38,12 +50,19 @@ public final class JarUtil {
      *            需要打包的目录(如 /tmp/demo-1.0.0/)
      * @param targetJarOrWar
      *            打包出的jar/war文件路径(如 /tmp/abc.jar)
+     * @param fileOrderSupport
+     *            文件排序序号提供者<br>
+     *            注:部分jar包会对jar包内的条目有顺序要求(如:spring-boot的jar包的lib目录下,lib包的顺序要和pom.xml中的声明顺序保持一致),
+     *                此时就可以使用此字段来实现排序了。
      * @return  打包出的jar/war文件路径
      */
-    public static String doJarWar(String srcDir, String targetJarOrWar) {
+    public static String doJarWar(String srcDir, String targetJarOrWar, FileOrderSupport fileOrderSupport) {
         File jarDirFile = new File(srcDir);
         // 枚举jarDir下的所有文件以及目录
         List<File> files = IOUtil.listSubFile(jarDirFile, 0);
+        if (fileOrderSupport != null) {
+            files = files.stream().sorted(Comparator.comparing(fileOrderSupport::obtainFileOrder)).collect(Collectors.toList());
+        }
         ZipOutputStream zos = null;
         OutputStream out = null;
         try {
@@ -65,7 +84,8 @@ public final class JarUtil {
                 // 目录,添加一个目录entry
                 if (file.isDirectory()) {
                     ZipEntry zipEntry = new ZipEntry(fileName + Constant.LINUX_FILE_SEPARATOR);
-                    zipEntry.setTime(System.currentTimeMillis());
+                    zipEntry.setTime(file.lastModified());
+                    zipEntry.setLastModifiedTime(FileTime.fromMillis(file.lastModified()));
                     zos.putNextEntry(zipEntry);
                     zos.closeEntry();
                 }
@@ -75,8 +95,9 @@ public final class JarUtil {
                     ZipEntry ze = new ZipEntry(fileName);
                     ze.setMethod(ZipEntry.STORED);
                     ze.setSize(bytes.length);
-                    ze.setTime(System.currentTimeMillis());
                     ze.setCrc(IOUtil.computeCrc32(bytes));
+                    ze.setTime(file.lastModified());
+                    ze.setLastModifiedTime(FileTime.fromMillis(file.lastModified()));
                     zos.putNextEntry(ze);
                     zos.write(bytes);
                     zos.closeEntry();
@@ -84,7 +105,8 @@ public final class JarUtil {
                 // 其它文件直接写入
                 else {
                     ZipEntry zipEntry = new ZipEntry(fileName);
-                    zipEntry.setTime(System.currentTimeMillis());
+                    zipEntry.setTime(file.lastModified());
+                    zipEntry.setLastModifiedTime(FileTime.fromMillis(file.lastModified()));
                     zos.putNextEntry(zipEntry);
                     byte[] bytes = IOUtil.toBytes(file);
                     zos.write(bytes);
@@ -123,7 +145,7 @@ public final class JarUtil {
      *            注:当entry对应jar或者war中的目录时,那么其值形如 BOOT-INF/classes/
      *            <br/>
      *            注:当entry对应jar或者war中的文件时,那么其值形如 BOOT-INF/classes/com/example/ssm/author/JustryDeng.class
-     * @return  解压出来的文件(包含目录)的完整路径
+     * @return  (按压缩文件中条目的顺序)解压出来的(有序的)文件(包含目录)的完整路径
      */
     public static <T extends Collection<String>> List<String> unJarWar(String jarWarPath, String targetDir,
                                                                        boolean delOldTargetDirIfAlreadyExist,
@@ -136,6 +158,9 @@ public final class JarUtil {
         guarantyDirExist(target);
         
         ZipFile zipFile = null;
+        // 此集合中的file会保留上一次修改时间,不会被当前解压操作覆盖
+        List<String> storeLastModifiedTimeList = new ArrayList<>();
+        Map<String, Long> filePthAndLastModifiedTimeMap = new HashMap<>(64);
         try {
             zipFile = new ZipFile(new File(jarWarPath));
             ZipEntry entry;
@@ -152,6 +177,9 @@ public final class JarUtil {
                 if (entry.isDirectory()) {
                     targetFile = new File(target, entryName);
                     guarantyDirExist(targetFile);
+                    String absolutePath = targetFile.getAbsolutePath();
+                    storeLastModifiedTimeList.add(absolutePath);
+                    filePthAndLastModifiedTimeMap.put(absolutePath, entry.getLastModifiedTime().toMillis());
                 } else {
                     // 有时遍历时,文件先于文件夹出来,所以也得保证目录存在
                     int lastSeparatorIndex = entryName.lastIndexOf(Constant.LINUX_FILE_SEPARATOR);
@@ -162,7 +190,10 @@ public final class JarUtil {
                     targetFile = new File(target, entryName);
                     byte[] bytes = IOUtil.toBytes(zipFile.getInputStream(entry));
                     IOUtil.toFile(bytes, targetFile, true);
-                    list.add(targetFile.getAbsolutePath());
+                    String absolutePath = targetFile.getAbsolutePath();
+                    list.add(absolutePath);
+                    storeLastModifiedTimeList.add(absolutePath);
+                    filePthAndLastModifiedTimeMap.put(absolutePath, entry.getLastModifiedTime().toMillis());
                 }
             }
         } catch (IOException e) {
@@ -170,6 +201,11 @@ public final class JarUtil {
         } finally {
             IOUtil.close(zipFile);
         }
+        for (String filePath : storeLastModifiedTimeList) {
+            Long lastModifiedTime = filePthAndLastModifiedTimeMap.get(filePath);
+            //noinspection ResultOfMethodCallIgnored
+            new File(filePath).setLastModified(lastModifiedTime == null ? System.currentTimeMillis() : lastModifiedTime);
+        }
         return list;
     }
     

+ 2 - 2
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/JavassistUtil.java

@@ -84,9 +84,9 @@ public final class JavassistUtil {
                     try {
                         ctMethod.insertBefore(
                                 "System.out.println(\"\\n " + TIPS +" \\n\");"
-                                + "\nSystem.exit(-1);"
-                                // 运行时,这一行内容不会被输出的
+                                // 也输出印章信息吧
                                 + "\nSystem.out.println(\"" + Constant.SEAL +"\");"
+                                + "\nSystem.exit(-1);"
                         );
                     } catch (CannotCompileException e) {
                         if ("no method body".equals(e.getMessage())) {

+ 0 - 125
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/RsaUtil.java

@@ -1,125 +0,0 @@
-package winter.com.ideaaedi.classwinter.util;
-
-import winter.com.ideaaedi.classwinter.author.JustryDeng;
-import winter.com.ideaaedi.classwinter.exception.ClassWinterException;
-
-import javax.crypto.Cipher;
-import java.nio.charset.StandardCharsets;
-import java.security.KeyFactory;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.X509EncodedKeySpec;
-import java.util.Base64;
-import java.util.Objects;
-
-/**
- * RSA 3072加解密
- *
- * @author {@link JustryDeng}
- * @since 2021/6/5 11:08:40
- */
-public class RsaUtil {
-    
-    /**
-     * 随机生成密钥对
-     *
-     * @return left-公钥;right-私钥
-     */
-    public static Pair<String, String> genKeyPair() {
-        KeyPairGenerator keyPairGen;
-        try {
-            // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
-            keyPairGen = KeyPairGenerator.getInstance("RSA");
-        } catch (NoSuchAlgorithmException e) {
-            throw new ClassWinterException(e);
-        }
-        // 初始化密钥对生成器,密钥大小为3072位
-        keyPairGen.initialize(3072, new SecureRandom());
-        // 生成一个密钥对,保存在keyPair中
-        KeyPair keyPair = keyPairGen.generateKeyPair();
-        // 得到私钥
-        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
-        // 得到公钥
-        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
-        // 得到私钥字符串
-        String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()), StandardCharsets.UTF_8);
-        String privateKeyString = new String(Base64.getEncoder().encode((privateKey.getEncoded())), StandardCharsets.UTF_8);
-        return Pair.of(publicKeyString, privateKeyString);
-    }
-    
-    /**
-     * RSA公钥加密
-     *
-     * @param str
-     *            要加密的字符串
-     * @param publicKey
-     *            公钥
-     *
-     * @return 密文
-     */
-    public static String encrypt(String str, String publicKey) {
-        Objects.requireNonNull(str, "str cannot be empty.");
-        Objects.requireNonNull(publicKey, "publicKey cannot be empty.");
-        //base64编码的公钥
-        byte[] decoded = Base64.getDecoder().decode(publicKey);
-        try {
-            RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
-            //RSA加密
-            Cipher cipher = Cipher.getInstance("RSA");
-            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
-            return Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8)));
-        } catch (Exception e) {
-            throw new ClassWinterException(e);
-        }
-    }
-    
-    /**
-     * RSA私钥解密
-     *
-     * @param cipherText
-     *            密文
-     * @param privateKey
-     *            私钥
-     *
-     * @return 明文
-     */
-    public static String decrypt(String cipherText, String privateKey) {
-        Objects.requireNonNull(cipherText, "cipherText cannot be empty.");
-        Objects.requireNonNull(privateKey, "privateKey cannot be empty.");
-        // 64位解码加密后的字符串
-        byte[] inputByte = Base64.getDecoder().decode(cipherText.getBytes(StandardCharsets.UTF_8));
-        // base64编码的私钥
-        byte[] decoded = Base64.getDecoder().decode(privateKey);
-        try {
-            RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
-            //RSA解密
-            Cipher cipher = Cipher.getInstance("RSA");
-            cipher.init(Cipher.DECRYPT_MODE, priKey);
-            return new String(cipher.doFinal(inputByte), StandardCharsets.UTF_8);
-        } catch (Exception e) {
-           throw new ClassWinterException(e);
-        }
-    }
-    
-    /**
-     * test
-     */
-    public static void main(String[] args) throws Exception {
-        //生成公钥和私钥
-        Pair<String, String> keyPair = genKeyPair();
-        //加密字符串
-        String message = "hello JustryDeng";
-
-        System.out.println("随机生成的公钥为: " + keyPair.getLeft());
-        System.out.println("随机生成的私钥为: " + keyPair.getRight());
-        String cipherText = encrypt(message, keyPair.getLeft());
-        System.out.println(message + "\t加密后的字符串为: " + cipherText);
-        String plainText = decrypt(cipherText, keyPair.getRight());
-        System.out.println("还原后的字符串为: " + plainText);
-    }
-}

+ 31 - 0
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/SimpleFileOrderSupport.java

@@ -0,0 +1,31 @@
+package winter.com.ideaaedi.classwinter.util;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 简单的文件排序提供者
+ *
+ * @author JustryDeng
+ * @since 2021/11/7 17:31:27
+ */
+public class SimpleFileOrderSupport implements FileOrderSupport {
+    
+    private final Map<File, Integer> fileOrderInfo = new HashMap<>(64);
+    
+    public SimpleFileOrderSupport(List<String> filePathList) {
+        if (filePathList == null || filePathList.size() == 0) {
+            return;
+        }
+        for (int i = 0; i < filePathList.size(); i++) {
+            fileOrderInfo.put(new File(filePathList.get(i)), i);
+        }
+    }
+    
+    @Override
+    public Integer fileOrder(File file) {
+        return fileOrderInfo.get(file);
+    }
+}

+ 1 - 1
class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/AllTest.java

@@ -32,7 +32,7 @@ public class AllTest {
         String tips = "方法已经被class-winter加密保护了,请不要直接使用java -jar xxx.jar启动项目,请使用java -javaagent:xxx.jar -jar xxx.jar启动项目.";
         String alreadyProtectedLibs = "encrypted-lib-have-pwd-1.0.0.jar:qwer123~";
         String debug = "true";
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " excludePrefix=" + excludePrefix

+ 2 - 2
class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/AlreadyProtectedLibs_Test.java

@@ -67,7 +67,7 @@ public class AlreadyProtectedLibs_Test {
         String originJarOrWar = projectRootDir + Constant.LINUX_FILE_SEPARATOR + "my-project-with-encrypted-lib-no-pwd.jar";
         String includePrefix = "non-exist";
         String alreadyProtectedLibs = "encrypted-lib-no-pwd-1.0.0.jar";
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " alreadyProtectedLibs=" + alreadyProtectedLibs
@@ -110,7 +110,7 @@ public class AlreadyProtectedLibs_Test {
         String includePrefix = "non-exist";
         String alreadyProtectedLibs = "encrypted-lib-have-pwd-1.0.0.jar:qwer123~";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " alreadyProtectedLibs=" + alreadyProtectedLibs

+ 2 - 2
class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/Debug_Test.java

@@ -36,7 +36,7 @@ public class Debug_Test {
         String originJarOrWar = projectRootDir + "boot-jar.jar";
         String includePrefix = "com";
         
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 ;
@@ -64,7 +64,7 @@ public class Debug_Test {
         String originJarOrWar = projectRootDir + "boot-jar.jar";
         String includePrefix = "com";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " debug=" + true

+ 2 - 2
class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/ExcludePrefix_Test.java

@@ -38,7 +38,7 @@ public class ExcludePrefix_Test {
         String originJarOrWar = projectRootDir + "boot-jar.jar";
         String includePrefix = "com.aspire.ssm.util.AesEncryptDecryptUtil,com.aspire.ssm.util.DbSecurityBeanUtil";
         
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " debug=" + true
@@ -72,7 +72,7 @@ public class ExcludePrefix_Test {
         String includePrefix = "com.aspire.ssm.util.AesEncryptDecryptUtil,com.aspire.ssm.util.DbSecurityBeanUtil";
         String excludePrefix = "com.aspire.ssm.util.DbSecurityBeanUtil";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " excludePrefix=" + excludePrefix

+ 1 - 1
class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/FinalName_Test.java

@@ -23,7 +23,7 @@ public class FinalName_Test {
         String includePrefix = "com";
         String finalName = "YiYaKaKa";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " finalName=" + finalName

+ 1 - 1
class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/IncludeLibs_Test.java

@@ -42,7 +42,7 @@ public class IncludeLibs_Test {
         String includePrefix = "org.springframework.aop.target.dynamic,com.google.common.xml";
         String includeLibs = "spring-aop-5.1.8.RELEASE.jar,guava-28.2-jre.jar";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " includeLibs=" + includeLibs

+ 1 - 1
class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/IncludePrefix_Test.java

@@ -39,7 +39,7 @@ public class IncludePrefix_Test {
         String originJarOrWar = projectRootDir + "boot-jar.jar";
         String includePrefix = "com.aspire.ssm.util";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " debug=" + true

+ 2 - 2
class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/OriginJarOrWar_Test.java

@@ -32,7 +32,7 @@ public class OriginJarOrWar_Test {
         String originJarOrWar = projectRootDir + "non-exist.jar";
         String includePrefix = "com.aspire.ssm.util";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " debug=" + true
@@ -58,7 +58,7 @@ public class OriginJarOrWar_Test {
         String originJarOrWar = projectRootDir + "boot-jar.jar";
         String includePrefix = "com.aspire.ssm.util";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " debug=" + true

+ 1 - 1
class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/Password_Test.java

@@ -23,7 +23,7 @@ public class Password_Test {
         String includePrefix = "com";
         String password = "pwd123";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " password=" + password

+ 2 - 2
class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/SupportFile_Test.java

@@ -42,7 +42,7 @@ public class SupportFile_Test {
         String originJarOrWar = projectRootDir + "normal-jar.jar";
         String includePrefix = "com";
         
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 ;
@@ -62,7 +62,7 @@ public class SupportFile_Test {
         String includePrefix = "com";
         String supportFile = projectRootDir + "help";
         
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " supportFile=" + supportFile

+ 3 - 3
class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/Tips_Test.java

@@ -32,7 +32,7 @@ public class Tips_Test {
         String originJarOrWar = projectRootDir + "boot-jar.jar";
         String includePrefix = "com";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 ;
@@ -55,8 +55,8 @@ public class Tips_Test {
         String tips = "[潘嘎之交] 潘: 你别怪潘叔说话比较直白, 网络上的东西都是虚拟的, 你把握不住, 孩子! 因为这里的水很深...";
     
         // 如果tips值由一些特殊字符(如空格等)的话,可以用windows双引号(linux单引号)引起来。
-        // java -jar class-winter-core-1.2.3.jar originJarOrWar=/boot-jar.jar includePrefix=com tips="[潘嘎之交] 潘: 你别怪潘叔说话比较直白, 网络上的东西都是虚拟的, 你把握不住, 孩子! 因为这里的水很深..."
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        // java -jar class-winter-core-2.0.0.jar originJarOrWar=/boot-jar.jar includePrefix=com tips="[潘嘎之交] 潘: 你别怪潘叔说话比较直白, 网络上的东西都是虚拟的, 你把握不住, 孩子! 因为这里的水很深..."
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " tips=" + (BashUtil.IS_WINDOWS ? "\"".concat(tips).concat("\"") : "'".concat(tips).concat("'"));

+ 5 - 5
class-winter-core/src/test/java/winter/com/ideaaedi/classwinter/War_Test.java

@@ -34,7 +34,7 @@ public class War_Test {
         String originJarOrWar = projectRootDir + "war-project.war";
         String includePrefix = "com";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 ;
@@ -62,7 +62,7 @@ public class War_Test {
         String includePrefix = "com";
         String password = "123456";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " password=" + password
@@ -93,7 +93,7 @@ public class War_Test {
         String alreadyProtectedLibs = "encrypted-lib-no-pwd.jar";
         String password = "oop857857";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " alreadyProtectedLibs=" + alreadyProtectedLibs
@@ -124,7 +124,7 @@ public class War_Test {
         String alreadyProtectedLibs = "encrypted-lib-have-pwd.jar:qwer123~";
         String password = "yiyakaka";
         
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " alreadyProtectedLibs=" + alreadyProtectedLibs
@@ -160,7 +160,7 @@ public class War_Test {
         String alreadyProtectedLibs = "encrypted-lib-have-pwd.jar:qwer123~";
         String debug = "true";
     
-        String startBat = "java -jar " + projectRootDir + "class-winter-core-1.2.3.jar"
+        String startBat = "java -jar " + projectRootDir + "class-winter-core-2.0.0.jar"
                 + " originJarOrWar=" + originJarOrWar
                 + " includePrefix=" + includePrefix
                 + " excludePrefix=" + excludePrefix

BIN
class-winter-core/src/test/resources/class-winter-core-2.0.0.jar


+ 1 - 1
class-winter-maven-plugin/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <groupId>com.idea-aedi</groupId>
         <artifactId>class-winter</artifactId>
-        <version>1.2.3</version>
+        <version>2.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 162 - 1
pom.xml

@@ -9,7 +9,7 @@
     </modules>
     <groupId>com.idea-aedi</groupId>
     <artifactId>class-winter</artifactId>
-    <version>1.2.3</version>
+    <version>2.0.0</version>
 
     <!-- 配置项目的基础信息 -->
     <name>class-winter</name>
@@ -27,6 +27,70 @@
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
     </properties>
 
+    <!--licenses信息-->
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+
+    <!--scm信息-->
+    <scm>
+        <url>https://gitee.com/JustryDeng/class-winter</url>
+        <connection>https://gitee.com/JustryDeng/class-winter.git</connection>
+    </scm>
+
+    <!--开发者信息-->
+    <developers>
+        <developer>
+            <name>JustryDeng</name>
+            <email>13548417409@163.com</email>
+        </developer>
+    </developers>
+
+    <distributionManagement>
+        <!-- 要发布到的snapshot仓库 -->
+        <snapshotRepository>
+            <!-- 通过此id定位maven配置文件settings.xml中配置的用户名密码,以登录指定的url -->
+            <id>ossrh</id>
+            <!--
+                特别注意: 其中地址s01.oss.sonatype.org是你在jira中提issue后,审核员告诉你的,
+                对应部分原文是:
+                com.idea-aedi has been prepared, now user(s) JustryDeng can:
+                Publish snapshot and release artifacts to s01.oss.sonatype.org
+                Have a look at this section of our official guide for deployment instructions:
+                https://central.sonatype.org/publish/publish-guide/#deployment
+
+                Please comment on this ticket when you've released your first component(s), so we can activate the sync to Maven Central.
+                Depending on your build configuration, this might happen automatically. If not, you can follow the steps in this section of our guide:
+                https://central.sonatype.org/publish/release/
+                可知,这个地址要根据它给的指引来填
+             -->
+            <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
+        </snapshotRepository>
+        <!-- 要发布到的仓库 -->
+        <repository>
+            <!-- 通过此id定位maven配置文件settings.xml中配置的用户名密码,以登录指定的url -->
+            <id>ossrh</id>
+            <!--
+                特别注意: 其中地址s01.oss.sonatype.org是你在jira中提issue后,审核员告诉你的,
+                对应部分原文是:
+                com.idea-aedi has been prepared, now user(s) JustryDeng can:
+                Publish snapshot and release artifacts to s01.oss.sonatype.org
+                Have a look at this section of our official guide for deployment instructions:
+                https://central.sonatype.org/publish/publish-guide/#deployment
+
+                Please comment on this ticket when you've released your first component(s), so we can activate the sync to Maven Central.
+                Depending on your build configuration, this might happen automatically. If not, you can follow the steps in this section of our guide:
+                https://central.sonatype.org/publish/release/
+                可知,这个地址要根据它给的指引来填
+             -->
+            <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+        </repository>
+    </distributionManagement>
+
     <build>
         <plugins>
             <!-- 打包源码 -->
@@ -43,6 +107,103 @@
                     </execution>
                 </executions>
             </plugin>
+
+            <!-- 打包javadoc -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>3.1.0</version>
+                <configuration>
+                    <!-- 解决(因javadoc写得不规范导致的)报错 -->
+                    <additionalOptions>
+                        <additionalOption>-Xdoclint:none</additionalOption>
+                    </additionalOptions>
+                    <!--
+                    解决乱码:
+                       在IDEA中,打开File | Settings | Build, Execution, Deployment | Build Tools | Maven | Runner
+                       在VM Options中添加-Dfile.encoding=GBK,切记一定是GBK。即使用UTF-8的话,依然是乱码,这是因为Maven的
+                       默认平台编码是GBK(通过mvn -version可看见)。
+                     -->
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>attach-javadocs</id>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- nexus流程处理插件 实现自动(deploy、release...)发布等 -->
+            <plugin>
+                <groupId>org.sonatype.plugins</groupId>
+                <artifactId>nexus-staging-maven-plugin</artifactId>
+                <version>1.6.7</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <!-- 通过此id定位maven配置文件settings.xml中配置的用户名密码,以登录指定的url -->
+                    <serverId>ossrh</serverId>
+                    <!--
+                        特别注意: 其中地址s01.oss.sonatype.org是你在jira中提issue后,审核员告诉你的,
+                        对应部分原文是:
+                        com.idea-aedi has been prepared, now user(s) JustryDeng can:
+                        Publish snapshot and release artifacts to s01.oss.sonatype.org
+                        Have a look at this section of our official guide for deployment instructions:
+                        https://central.sonatype.org/publish/publish-guide/#deployment
+
+                        Please comment on this ticket when you've released your first component(s), so we can activate the sync to Maven Central.
+                        Depending on your build configuration, this might happen automatically. If not, you can follow the steps in this section of our guide:
+                        https://central.sonatype.org/publish/release/
+                        可知,这个地址要根据它给的指引来填
+                     -->
+                    <nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
+                    <autoReleaseAfterClose>true</autoReleaseAfterClose>
+                </configuration>
+            </plugin>
+
+            <!-- 发布到release仓库的部署插件 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-release-plugin</artifactId>
+                <version>2.5.3</version>
+                <configuration>
+                    <autoVersionSubmodules>true</autoVersionSubmodules>
+                    <useReleaseProfile>false</useReleaseProfile>
+                    <releaseProfiles>release</releaseProfiles>
+                    <goals>deploy</goals>
+                </configuration>
+            </plugin>
+
+            <!-- gpg签名认证 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-gpg-plugin</artifactId>
+                <version>1.6</version>
+                <executions>
+                    <execution>
+                        <id>sign-artifacts</id>
+                        <phase>verify</phase>
+                        <goals>
+                            <goal>sign</goal>
+                        </goals>
+                        <!--
+                            注: 如果不主动指定gpg.exe的话,那么可能(因为和idea内部发生了未知冲突)报错
+                            Cannot run program "gpg.exe": CreateProcess error=2, 系统找不到指定的文件。
+                            注: 当然,如果你直接用的git bash之类的工具执行mvn,而不是用idea提供的maven功能
+                                的话,你也可以不指定executable。
+                         -->
+                        <configuration>
+                            <executable>C:/Program Files (x86)/GnuPG/bin/gpg.exe</executable>
+                            <!--
+                                指定GPG 代表公钥的密钥id
+                                注:因为我们可能拥有多个GPG密钥对,所以我们需要指定使用哪一个
+                            -->
+                            <passphrase>F4A9FB7A887DCB32F185DBEF3D8B00493FAFC7F9</passphrase>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 </project>