`
cleaneyes
  • 浏览: 336463 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Java

 
阅读更多

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中实现的方法.
Java调用本地方法(JNI浅谈)
 
由此即实现了封装已写好的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,输出结果如图所示:
Java调用本地方法(JNI浅谈)
 
至此本人的JNI调用已经写好的DLL文件测试成功,并与不久将此用于项目开发中.
 
分享到:
评论

相关推荐

    JAVA_API1.6文档(中文)

    java.lang.management 提供管理接口,用于监视和管理 Java 虚拟机以及 Java 虚拟机在其上运行的操作系统。 java.lang.ref 提供了引用对象类,支持在某种程度上与垃圾回收器之间的交互。 java.lang.reflect 提供类...

    Java 面经手册·小傅哥.pdf

    这是一本以面试题为入口讲解 Java 核心内容的技术书籍,书中内容极力的向你证实代码是对数学逻辑的具体实现。当你仔细阅读书籍时,会发现Java中有大量的数学知识,包括:扰动函数、负载因子、拉链寻址、开放寻址、...

    java源码包---java 源码 大量 实例

    Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM...

    JAVA上百实例源码以及开源项目

     Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...

    java源码包2

    Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行...

    java源码包4

    Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行...

    java源码包3

    Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行...

    java api最新7.0

    JAVA开发人员最新版本7.0 api文档!本文档是 Java Platform Standard Edition 7 的 API !Java 1.7 API的中文帮助文档。 深圳电信培训中心 徐海蛟博士教学用api 7.0中文文档。支持全文检索,在线即时查询。 里面列...

    java开源包11

    JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...

    java开源包4

    JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...

    java开源包6

    JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...

    java开源包9

    JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...

    java开源包5

    JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...

    java开源包8

    JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...

    java开源包10

    JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...

    Java开发技术大全(500个源代码).

    HelloWorldApp.java 第一个用Java开发的应用程序。 firstApplet.java 第一个用Java开发的Applet小程序。 firstApplet.htm 用来装载Applet的网页文件 第2章 示例描述:本章介绍开发Java的基础语法知识。 ...

    java开源包1

    JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...

    java开源包3

    JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...

    Java 中文入门学习手册合集[chm版]

    第一章 Java语言的产生及其特点 第二章 Java程序开发与运行环境 第三章 Java程序设计基础 第四章 Java应用程序的基本框架 第五章 Java的类 第六章 Java图形用户接口 第七章 多线程 第八章 Java的"异常" 第九...

Global site tag (gtag.js) - Google Analytics