最近课程作业完成MD5加密的DLL编写,并使用Java调用DLL,中间遇到几个坑与君共勉。
java native interface JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架,比JNI更好用,JNI偏底层,JNA更友好。 JNA下载地址:https://github.com/java-native-access/jna 找到Download下载第一个就OK
以eclipse为例,右键项目->Properties->Java Build Path->Libraries->Add External JARs 选择JNA
1、编写charReference类,该类继承com.sun.jna.ptr.ByReference类,该类主要负责Java数据类型到C++中char *类型对应
import com.sun.jna.ptr.ByReference; public class charReference extends ByReference{ public charReference() { this((byte)0);//无 } public charReference(byte value) { super(1000); this.setValue(value); } public void setValue(byte value) { this.getPointer().setByte(0L, value); } public byte getValue() { return this.getPointer().getByte(0L); } public void Init(String input) { for(int i=0;i<input.length();i++) { this.getPointer().setChar((long)i, input.charAt(i));//字符串初始化 } } public void Init(byte[] bytes) { for(int i=0;i<bytes.length;i++) { this.getPointer().setByte((long)i, bytes[i]);//字节数组初始化 } } }因为char可能是中文汉字,中文汉字占两个字节,在setChar时并不会将两个字节都传到对象中,所以有中文时需要先将字符串转化成字节数组再传。
2、声明接口
import com.sun.jna.*; import com.sun.jna.ptr.PointerByReference; import tools.charReference; public interface PORT extends Library{ PORT INSTANTCE=(PORT)Native.loadLibrary("MD5",PORT.class);//MD5为DLL文件名 public void MD5(charReference input,charReference output); }将DLL文件放在项目bin文件夹下
3、MD5的JAVA实现
import java.io.UnsupportedEncodingException; import com.sun.jna.*; import com.sun.jna.ptr.PointerByReference; import tools.byteToString; import tools.PORT; import tools.charReference; public class MD5Encoder { //获得byte数组 private static byte[] getBytes(String input) throws UnsupportedEncodingException { int byteLen=0; byte[] bytes=new byte[3*input.length()]; for(int i=0;i<input.length();i++) { char now=input.charAt(i); byte[] nowCharBytes=null; if(isChinese(now)) { nowCharBytes=(""+now).getBytes("utf-8"); }else { nowCharBytes=(""+now).getBytes(); } for(int j=0;j<nowCharBytes.length;j++) { bytes[byteLen++]=nowCharBytes[j]; } } return bytes; } //判断是否为中文 private static final boolean isChinese(char c) { Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) { return true; } return false; } //加密 public static String encoder(String inputString) throws UnsupportedEncodingException { charReference output=new charReference(); charReference input=new charReference(); input.Init(getBytes(inputString)); PORT.INSTANTCE.MD5(input, output); String outputString=""; for(int i =0;i<16;i++) { outputString=outputString+byteToString.bytesToHexString(output.getPointer().getByte(i)); } return outputString; } //测试 public static void main(String[] args) throws UnsupportedEncodingException { charReference output=new charReference(); charReference input=new charReference(); String x="zx哈哈"; input.Init(getBytes(x)); PORT.INSTANTCE.MD5(input, output); String outputString=""; for(int i =0;i<16;i++) { outputString=outputString+byteToString.bytesToHexString(output.getPointer().getByte(i)); } System.out.println(outputString); } }byteToString.byteToHexString为另一个类中的字节数组转化成字符串的函数
public static String bytesToHexString(byte src) { int v = src & 0xFF; String hv = Integer.toHexString(v); if(hv.length()==1) { return "0"+hv; } return hv; }运行结果: 与某网站(https://md5jiami.51240.com/)加密结果相同