Java调用本地方法(JNI浅谈)

(2006-11-27 14:55:36)

  分类: Java类文章

               本人在项目开发实践中的总结和体会   
    前段时间公司要求将指纹应用到web上,之前都是用delphi开发并实施,采用的是C/S模式,但是现在已经无法满足需求,只能应用B/S模式.但是使用B/S模式的局限性体现在三方面,
    其一:采集指纹数据和指纹比对身份认证还是无法直接利用web实现,毕竟和底层设备打交道是很难在web上实现的,考虑还是使用delphi组件采集和比对指纹,人员信息和其他业务利用web传输显示.
    其二:数据库中的指纹数据都是压缩后的bmp文件,而数据解压缩是调用指纹算法研究部门用VC写的一个DLL库,在delphi中调用DLL是比较简单的,但是如果将指纹数据显示到web上的话就必须利用java调用解压缩DLL文件,而java调用本地方法最简单的方法只能是JNI(Java Native Interface ).
    下面主要介绍一下我是如何利用JNI调用已经写好的DLL文件.
     思路:JNI调用本地方法的话,必须先在JAVA中声明本地方法,然后用VC实现本地方法,而在VC中的本地方法必须符合JNI的命名规则才会被JNI识别并调用,但是现在是已经有一个用VC写好的DLL,当然我不可能按照JNI的规则重写该DLL,不现实!我想应该可以用VC将已经写好的DLL封装一下,即我写一个中间DLL符合JNI规则的DLL应该可以的.
     第一步: JAVA中声明本地方法
     package com.cchongda.decompress;
     public class TestDecompress {
     static{
        System.loadLibrary("testdecompress");//加载动态库testdecompress.dll 
     }
     public native byte[] decompress(byte[] inbs,int hh,int ww);
     }
     第二步: 在定义一个类,该类中只声明两个byte[] 一个用来存放压缩的指纹数据,一个用来接受调用解压缩方法解压后的指纹数据.
     package com.cchongda.decompress;
     public class InputByte {
     public byte[] inbs;
     public byte[] outbs;
     public InputByte() {
     }
     }
     第三步:编译TestDecompress类,生成TestDecompress.class文件,然后利用javah -classpath 类路径包名.类名编译TestDecompress.class生成包名_类名.h格式的C头文件,我的头文件是 com_cchongda_decompress_TestDecompress.h
该将该头文件copy到VC++6.0下的VC98目录下的include文件夹下或者放到你的DLL工程目录下,同时将D:\j2sdk1.4.2_13\include\下的jni.h和win32目录下的jni_md.h两个头文件都copy到VC++6.0下的VC98目录下的include文件夹下或者放到你的DLL工程目录下.
     类生成的TestDecompress.h头文件内容如下:
   /* DO NOT EDIT THIS FILE - it is machine generated */
    #include
    /* Header for class com_cchongda_decompress_TestDecompress */
    #ifndef _Included_com_cchongda_decompress_TestDecompress
    #define _Included_com_cchongda_decompress_TestDecompress
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_cchongda_decompress_TestDecompress
     * Method:    decompress
     * Signature: ([BII)[B
    */
    //这个地方就是java中声明的本地方法原型
    JNIEXPORT jbyteArray JNICALL      Java_com_cchongda_decompress_TestDecompress_decompress
  (JNIEnv *, jobject, jbyteArray, jint, jint);
   #ifdef __cplusplus
   }
   //
    #endif
    #endif
   第四步:封装已经写好的dll,在VC中新建一个win32 Dynamic-LinkLibrary工程,工程名与java中将要加载的dll名称一样为"testdecompress",在生成的testdecompress.cpp文件中敲入如下代码:(红色为我敲入的代码)
     #include "stdafx.h"
     (1)#include "com_cchongda_decompress_TestDecompress.h"
(2)extern "C" int _stdcall Decompress(unsigned char *outimg,char* ezwimg,int hh,int ww);
BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
    return TRUE;
}
(3)JNIEXPORT jbyteArray JNICALL Java_com_cchongda_decompress_TestDecompress_decompress(JNIEnv * env,jobject obj,jbyteArray barr,jint hh,jint ww)
{
 int i =1;
 unsigned char * buffer = new BYTE[92160];
 jbyteArray temparr;
 temparr = env->NewByteArray(92160);
 char * parr;
 jbyte *arr = env->GetByteArrayElements(barr,0);
 parr = (char *)arr;
 /*FILE *fp;
 fp = fopen("C:\\11.dat","w");
 fwrite(parr,1,4610,fp);
 fclose(fp);*/
    i=Decompress(buffer,parr,hh,ww);
 //printf("%d",i);
 env->SetByteArrayRegion(temparr, 0, 92160, (const signed char *)buffer);
 env->ReleaseByteArrayElements(barr, (signed char *)parr, 0);
 return temparr;
}
(1)该语句是将class文件生成的.h头文件引进来,因为在那个头文件有对在java中声明的本地方法的原型.
(2)该语句是将已经写好的数据解压缩dll中的解压缩方法原型的声明,在项目中要将已写好的dll导入项目中,我采用的是隐式加载即引入头文件(在.cpp中声明函数原型也可)和.lib文件,图中红色的为引进来的.lib文件
(3)该方法即是本地方法的实现,其中调用了Decompress(buffer,parr,hh,ww)该方法是在Exwdll.dll中实现的方法.
 
由此即实现了封装已写好的Exwdll.dll,编译该testdecompress.cpp文件后,在Debug文件下生成一个tesedecompress.dll文件,将该文件copy到java项目下开始测试.
   第五步:写java测试代码
   (1)数据库连接类DbConnect
package com.cchongda.decompress;
import java.sql.*;
public class DbConnect {
  public DbConnect() {
  }
  public  Connection conn=null;
 public Statement stat=null;
 public  PreparedStatement pstat=null;
 public  ResultSet rs=null;
 private String Driver="com.mysql.jdbc.Driver";
 private String url="jdbc:mysql://192.101.1.138:3306/fingerdb";
 {
   try{
     Class.forName(Driver).newInstance();
   }
   catch(java.lang.IllegalAccessException iae){
     iae.printStackTrace();
   }
   catch(java.lang.ClassNotFoundException cnf){
     cnf.printStackTrace();
   }
   catch(java.lang.InstantiationException ie){
     ie.printStackTrace();
   }
 }
 public Connection getConn() {
   try{
     this.conn = java.sql.DriverManager.getConnection(url, "root", "");
   }
   catch(java.sql.SQLException e){
     e.printStackTrace();
   }
   return conn;
 }
 public Statement getStat(){
   Statement stat = null;
   try{
     stat = this.getConn().createStatement();
   }
   catch(SQLException sqle){
     sqle.printStackTrace();
   }
   return stat;
 }
 public ResultSet getRs(String sql){
 //  String sql="select htzw1 from zwzpxxb where sbh=''";
 ResultSet rs=null;
   try{
     rs = stat.executeQuery(sql);
   }
   catch(java.sql.SQLException sqle){
     sqle.printStackTrace();
   }
   return rs;
 }
}
(2)主类提供入口函数
package com.cchongda.decompress;
import java.sql.*;
import java.io.*;
public class Test {
  public Test() {
  }
  public static void main(String[] args){
    FileOutputStream fos = null;
    TestDecompress td = new TestDecompress();
    InputByte ib = new InputByte();
    int hh = 360;
    int ww = 256;
    File file = new File("C:/uuu.bmp");
    try{
      fos  = new FileOutputStream(file);
    }
    catch(Exception e){
      e.printStackTrace();
    }
    DbConnect dbc = new DbConnect();
    try{
      dbc.stat = dbc.getConn().createStatement();
    }catch(java.sql.SQLException sqle){
      sqle.printStackTrace();
    }
    String sql1= "select wjt from wjt";
    String sql2 = "select htzw1 from zwzpxxb where sbh='A026010239'";
    Blob blob = null;
    ResultSet rs1 = dbc.getRs(sql1);
    try{
      if (rs1.next()) {
        blob = rs1.getBlob("wjt");
        System.out.println("文件头的字节数:"+blob.length());
      }
      fos.write(blob.getBytes(1,(int)blob.length()),0,(int)blob.length());
    }catch(Exception e){
      e.printStackTrace();
    }
    blob =null;
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ResultSet rs2 = dbc.getRs(sql2);
    try{
      if (rs2.next()) {
        blob = rs2.getBlob("htzw1");
        System.out.println("文件体的字节数:"+blob.length());
        bos.write(blob.getBytes(1,(int)blob.length()),0,(int)blob.length());
        ib.inbs=bos.toByteArray();
        System.out.println("进入的字节数"+ib.inbs.length);
       // System.out.print(ib.outbs.length);
        bos.close();
      }
    }catch(Exception e){
      e.printStackTrace();
    }
    ib.outbs= td.decompress(ib.inbs,hh,ww);
    try{
      System.out.println("解压缩后的字节数:"+ib.outbs.length);
      fos.write(ib.outbs, 0, ib.outbs.length);
      fos.flush();
      fos.close();
    }
    catch(Exception e){
      e.printStackTrace();
    }
  }
}
该过程是从数据库中读取一个未压缩的指纹数据文件头和压缩的指纹数据文件体,调用解压缩方法解压后将完整的指纹数据输出到c:\uuu.bmp,输出结果如图所示:
 
至此本人的JNI调用已经写好的DLL文件测试成功,并与不久将此用于项目开发中.

java本地方法如何调用其他程序函数,方法详解2的更多相关文章

  1. Python3调用C程序(超详解)

    Python3调用C程序(超详解) Python为什么要调用C? 1.要提高代码的运算速度,C比Python快50倍以上 2.对于C语言里很多传统类库,不想用Python重写,想对从内存到文件接口这样 ...

  2. java本地方法如何调用其他程序函数,方法详解

    JNI是Java Native Interface的缩写,中文为JAVA本地调用.从Java 1.1 开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许J ...

  3. java 通过反射机制调用某个类的方法

    package net.xsoftlab.baike; import java.lang.reflect.Method; public class TestReflect {     public s ...

  4. java多态性方法的重写Overriding和重载Overloading详解

    java多态性方法的重写Overriding和重载Overloading详解 方法的重写Overriding和重载Overloading是Java多态性的不同表现.重写Overriding是父类与子类 ...

  5. C#虚函数virtual详解

    在面向对象编程中,有两种截然不同的继承方式:实现继承和接口继承.在实现继承时候,在Java中,所有函数默认都是virtual的,而在C#中所有函数并不默认为virtual的,但可以在基类中通过声明关键 ...

  6. Scala进阶之路-Scala函数篇详解

    Scala进阶之路-Scala函数篇详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传值调用和传名调用 /* @author :yinzhengjie Blog:http: ...

  7. 转载 LayoutInflater的inflate函数用法详解

    http://www.open-open.com/lib/view/open1328837587484.html LayoutInflater的inflate函数用法详解 LayoutInflater ...

  8. Java NIO 的前生今世 之四 NIO Selector 详解

    Selector Selector 允许一个单一的线程来操作多个 Channel. 如果我们的应用程序中使用了多个 Channel, 那么使用 Selector 很方便的实现这样的目的, 但是因为在一 ...

  9. php中的PDO函数库详解

    PHP中的PDO函数库详解 PDO是一个“数据库访问抽象层”,作用是统一各种数据库的访问接口,与mysql和mysqli的函数库相比,PDO让跨数据库的使用更具有亲和力:与ADODB和MDB2相比,P ...

随机推荐

  1. 用python简单处理图片(4):图像中的像素访问

    前面的一些例子中,我们都是利用Image.open()来打开一幅图像,然后直接对这个PIL对象进行操作.如果只是简单的操作还可以,但是如果操作稍微复杂一些,就比较吃力了.因此,通常我们加载完图片后,都 ...

  2. [MetaHook] R_SparkEffect

    By hzqst void R_SparkEffect(float *pos, int count, int velocityMin, int velocityMax) { efx.R_SparkSt ...

  3. 三种实例化委托的方式(C# 编程指南)

    1.定义的委托和方法 delegate void TestDelegate(string s); static void M(string s) { Console.WriteLine(s); } 2 ...

  4. Django1.8教程——从零开始搭建一个完整django博客(一)

    第一个Django项目将是一个完整的博客网站.它和我们博客园使用的博客别无二致,一样有分类.标签.归档.查询等功能.如果你对Django感兴趣的话,这是一个绝好的机会.该教程将和你一起,从零开始,搭建 ...

  5. unity3d 扩展NGUI —— 限制UI点击响应间隔

    当某个按钮按下后给服务器发送某条消息 如果玩家短时间内疯狂点击按钮很多次,这将会给服务器发送很多条无用数据 不但增加了服务器的压力,发送数据还浪费流量,甚至可能引发一些莫名其妙的bug 所以,限制UI ...

  6. Bootstrap系列 -- 19. 焦点状态

    表单主要用来与用户沟通,好的表单就能更好的与用户进行沟通,而好的表单一定离不开表单的控件状态. 表单状态的作用: 每一种状态都能给用户传递不同的信息,比如表单有焦点的状态可以告诉用户可以输入或选择东西 ...

  7. [poj3046]Ant Counting(母函数)

    题意: S<=x1+x2+...+xT<=B 0<=x1<=N1 0<=x2<=N2 ... 0<=xT<=NT 求这个不等式方程组的解的个数. 分析: ...

  8. 网站开发技巧, 使用byte[]持久化用户个性设置

    场景, 网站用户的个性化配置较多, 而且容易发生增加和改变, 如何在数据库保存是个问题. 为了避免数据库表字段经常变更, 我们设计在表增加一个varbinary(max)字段存储个性化配置. 个性化的 ...

  9. “耐撕”团队记账本 剧透

    β发布之后,我们团队开始fork"OneZero"团队的记账本程序.我们在原来的基础上添加了以下功能: 下面是我们团队记账本程序演示的视频:http://v.youku.com/v ...

  10. OpenLayers中地图缩放级别的设置方法

    来源于:http://www.cnblogs.com/sailheart/archive/2011/03/15/1984519.html 一.概述 在OpenLayers中,地图必须具有一个缩放级别的 ...