aardio调用java语言

发布时间 2023-10-27 19:03:12作者: 周文豪

一、引入java

默认只要在 aardio 中调用

import java; 

就会自动搜索系统可用的 JRE,如果没有找到 JRE,会自动导入 java.jre.v8 扩展库,并自动安装 OpenJDK JRE v8 。

注:如果系统已经安装了java6,就会用系统自带的java6,而不会自动安装OpenJDK JRE v8

项目经验:项目开发过程中就遇到这样的问题:由于java工具类是用java8编译的,在没有安装java6的电脑,aardio调用java是正常的,因为会自动安装java8。但是在安装了java6的电脑,aardio就无法调用java,因为系统已经存在java6了,就不会自动安装java8,由于用java8编译成的class文件中部分代码(如Base64在java6中没有)在java6中无法运行,导致aardio无法调用java,从而导致插件无法使用。后来将工具类用java6编译后,就能正常使用了。

如果您希望发布的软件自带 Java 运行时,或者指定 JRE 的版本,只要在 aardio 中导入其他版本 JRE 的扩展库就可以,例如运行

import java.jre.v8ora

就可以自动绑定 Oracle Java 8 运行时,软件运行会自动查找用户电脑上符合要求的 JRE,如果没有找到会全自动地安装和部署好,开发者要做的,仅仅就是写几句代码,把 EXE 简单地分发给用户就可以了。

二、调用java案例

import java;
var jvm = ..java();  // 创建 Java 虚拟机
var RSA = jvm.import("aardio.util.RSAUtils"); // 导入 Java 类    
return RSA .encryptByPublicKey(..web.json.stringify(sourceData),publicKey);

注意:由于class文件中的encryptByPublicKey为静态方法,故不用实例化RSA,直接用RSA调用encryptByPublicKey方法。当然也可以先实例化,在调用

import java;
var jvm = ..java();  // 创建 Java 虚拟机
var RSA = jvm.import("aardio.util.RSAUtils"); // 导入 Java 类    
var rsa = RSA(); // 实例化
return rsa .encryptByPublicKey(..web.json.stringify(sourceData),publicKey);

RSAUtils.class文件如下:

package aardio.util;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.xml.bind.DatatypeConverter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class RSAUtils {
    // RSA 最大加密明文大小
    private static final int MAX_ENCRYPT_BLOCK = 117;
    // RSA 最大解密密文大小
    private static final int MAX_DECRYPT_BLOCK = 128;
    /**
     * 密钥长度 于原文长度对应 以及越长速度越慢
     */
    private final static int KEY_SIZE = 1024;
    private final static String PUBLIC_KEY ="PUBLIC_KEY";
    private final static String PRIVATE_KEY ="PRIVATE_KEY";
    /**
     * 用于封装随机产生的公钥与私钥
     */
    private static Map<String, String> keyMap = new HashMap<String,String>();

    /**
     * 随机生成密钥对
     */
    public static Map<String,String> genKeyPair() throws NoSuchAlgorithmException {
        // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        // 初始化密钥对生成器
        keyPairGen.initialize(KEY_SIZE, new SecureRandom());
        // 生成一个密钥对,保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 得到私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 得到公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        String publicKeyString = DatatypeConverter.printBase64Binary(publicKey.getEncoded());
//        String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());
        // 得到私钥字符串
        String privateKeyString = DatatypeConverter.printBase64Binary(privateKey.getEncoded());
//        String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());
        // 将公钥和私钥保存到Map

        keyMap.put(aardio.util.RSAUtils.PUBLIC_KEY, publicKeyString);
        // 将私钥和私钥保存到Map
        keyMap.put(aardio.util.RSAUtils.PRIVATE_KEY, privateKeyString);
        return keyMap;
    }

    /**
     * 得到公钥
     * @return
     */
    public static String getPublicKey(){
        return keyMap.get(aardio.util.RSAUtils.PUBLIC_KEY);
    }

    /**
     * 得到私钥
     * @return
     */
    public static String getPrivateKey(){
        return keyMap.get(aardio.util.RSAUtils.PRIVATE_KEY);
    }
    public static String encryptByPublicKey(String sourceData, String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException {
        byte[] dataBytes = sourceData.getBytes(Charset.forName("UTF-8"));
//        byte[] keyBytes = Base64.getDecoder().decode(publicKey);
        byte[] keyBytes = DatatypeConverter.parseBase64Binary(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key pubK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubK);
        int inputLen = dataBytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(dataBytes, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
//        String encryptData = Base64.getEncoder().encodeToString(out.toByteArray());
        String encryptData = DatatypeConverter.printBase64Binary(out.toByteArray());
        out.close();
        return encryptData;
    }

    public static String decryptByPublicKey(String encryptData, String pubKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException {
//        byte[] sourceBytes = Base64.getDecoder().decode(encryptData);
        byte[] sourceBytes = DatatypeConverter.parseBase64Binary(encryptData);
//        byte[] keyBytes = Base64.getDecoder().decode(pubKey);
        byte[] keyBytes = DatatypeConverter.parseBase64Binary(pubKey);
        X509EncodedKeySpec x50KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key pubK = keyFactory.generatePublic(x50KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, pubK);
        int inputLen = sourceBytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(sourceBytes, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(sourceBytes, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        String decryptedData = out.toString("UTF-8");
        out.close();
        return decryptedData;
    }

}
View Code

注意:package的包为aardio.util,而不是IDEA中的包路径。

RSAUtils.class在aardio中的包结构如下:

注意:如果系统中已经安装了java6,那么java的工具类需要用java6进行编译。

注意:如果java工具类中要引入其他包,如下MD5Utils.java引入了

import org.apache.commons.codec.binary.Hex;

故需要将commons-codec-1.15.jar放到aardio.util目录下

MD5Utils.java如下所示:

package aardio.util;

import org.apache.commons.codec.binary.Hex;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;

public class MD5Utils {

    public static Random random = new SecureRandom();


    /**
     * MD5加密
     * @param str 待加密数据项
     * @return
     */
    public static String getMD5(String str) {
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.reset();
            messageDigest.update(str.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            System.out.println("NoSuchAlgorithmException caught!");
            System.exit(-1);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        byte[] byteArray = messageDigest.digest();
        StringBuffer md5StrBuff = new StringBuffer();
        for (int i = 0; i < byteArray.length; i++) {
            if (Integer.toHexString(0xFF & byteArray[i]).length() == 1) {
                md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));
            }else {
                md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
            }
        }
        return md5StrBuff.toString();
    }

    /**
     * 不加盐验证md5加密结果
     * @param password 原始密码
     * @param md5str 加密后的值
     * @return
     * @throws Exception
     */
    public static boolean getVerifyMD5(String password, String md5str) throws Exception{
        return getMD5(password).equals(md5str);
    }

    /**
     * 加盐MD5算法
     * @param password
     * @return
     */
    public static String getSaltMD5(String password) throws Exception{
        StringBuilder sb = new StringBuilder(16);
        sb.append(random.nextInt(99999999)).append(random.nextInt(99999999));
        int len = sb.length();
        if(len < 18){
            int diffLen = 16 - len;
            for(int i = 0; i < diffLen; i ++){
                sb.append(0);
            }
        }
        String salt = sb.toString();
        password = md5Hex(password + salt);
        char[] cs = new char[48];
        for (int i = 0; i < 48; i += 3) {
            cs[i] = password.charAt(i / 3 * 2);
            char c = salt.charAt(i / 3);
            cs[i + 1] = c;
            cs[i + 2] = password.charAt(i / 3 * 2 + 1);
        }
        return String.valueOf(cs);
    }

    /**
     * 使用Apache的Hex类实现Hex(16进制字符串和)和字节数组的互转
     * @param str 原明文字符串
     * @return 转换后的字符
     */
    private static String md5Hex(String str) throws Exception{
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digest = md.digest(str.getBytes());
        return new String(new Hex().encode(digest));
    }

    /**
     * 验证加盐后是否和原文一致
     * @param password 原始密码
     * @param md5str md5后值
     * @return
     */
    public static boolean getSaltverifyMD5(String password, String md5str) throws Exception{
        char[] cs1 = new char[32];
        char[] cs2 = new char[16];
        for (int i = 0; i < 48; i += 3) {
            cs1[i / 3 * 2] = md5str.charAt(i);
            cs1[i / 3 * 2 + 1] = md5str.charAt(i + 2);
            cs2[i / 3] = md5str.charAt(i + 1);
        }
        String salt = new String(cs2);
        return md5Hex(password + salt).equals(String.valueOf(cs1));
    }

    /**
     * 获取文件的md5值 ,有可能不是32位
     * @param filePath    文件路径
     * @return
     * @throws FileNotFoundException
     */
    public static String md5HashCode(String filePath) throws FileNotFoundException{
        FileInputStream fis = new FileInputStream(filePath);
        return md5HashCode(fis);
    }

    /**
     * 保证文件的MD5值为32位
     * @param filePath    文件路径
     * @return
     * @throws FileNotFoundException
     */
    public static String md5HashCode32(String filePath) throws FileNotFoundException{
        FileInputStream fis = new FileInputStream(filePath);
        return md5HashCode32(fis);
    }

    /**
     * java获取文件的md5值
     * @param fis 输入流
     * @return
     */
    public static String md5HashCode(InputStream fis) {
        try {
            //拿到一个MD5转换器,如果想使用SHA-1或SHA-256,则传入SHA-1,SHA-256
            MessageDigest md = MessageDigest.getInstance("MD5");

            //分多次将一个文件读入,对于大型文件而言,比较推荐这种方式,占用内存比较少。
            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = fis.read(buffer, 0, 1024)) != -1) {
                md.update(buffer, 0, length);
            }
            fis.close();
            //转换并返回包含16个元素字节数组,返回数值范围为-128到127
            byte[] md5Bytes  = md.digest();
            BigInteger bigInt = new BigInteger(1, md5Bytes);//1代表绝对值
            return bigInt.toString(16);//转换为16进制
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * java计算文件32位md5值
     * @param fis 输入流
     * @return
     */
    public static String md5HashCode32(InputStream fis) {
        try {
            //拿到一个MD5转换器,如果想使用SHA-1或SHA-256,则传入SHA-1,SHA-256
            MessageDigest md = MessageDigest.getInstance("MD5");

            //分多次将一个文件读入,对于大型文件而言,比较推荐这种方式,占用内存比较少。
            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = fis.read(buffer, 0, 1024)) != -1) {
                md.update(buffer, 0, length);
            }
            fis.close();

            //转换并返回包含16个元素字节数组,返回数值范围为-128到127
            byte[] md5Bytes  = md.digest();
            StringBuffer hexValue = new StringBuffer();
            for (int i = 0; i < md5Bytes.length; i++) {
                int val = ((int) md5Bytes[i]) & 0xff;//解释参见最下方
                if (val < 16) {
                    /**
                     * 如果小于16,那么val值的16进制形式必然为一位,
                     * 因为十进制0,1...9,10,11,12,13,14,15 对应的 16进制为 0,1...9,a,b,c,d,e,f;
                     * 此处高位补0。
                     */
                    hexValue.append("0");
                }
                //这里借助了Integer类的方法实现16进制的转换
                hexValue.append(Integer.toHexString(val));
            }
            return hexValue.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    public static void main(String[] args) {
        System.out.println(getMD5("crpts123@"));
    }
}
View Code