java JNI调用C++代码(给出一个简单java application示例和实际java web项目过程及错误解决)(二)

二、java web 服务器(tomcat)调用图像处理C++代码项目实例

转载请注明:https://blog.csdn.net/xitie8523/article/details/80009821

简单JNI示例:https://blog.csdn.net/xitie8523/article/details/79926948

菜鸟在开始写代码时担心的是 

1、我图像处理的方法封装了那么多方法,不可能一个一个声明为native,如果我只声明最后封装的那个方法,其他的.h文件不管,会不会出问题?

2、图像处理用了opencv库,在java里面是不是也要配置一下?

3、处理个图像很费事的,会不会崩了?

4、除了让C++方法能调用,还要把它整合到服务器里调用,在服务器哪里调用,怎么把数据返回?

叨叨完了,正文:

1)第一步同样是编写java源码

事先已经搭好了服务器和客户端,由Upload实现互传图片,在包trans下新建一个java类GrainCutDll,其中GrainCutDll是我C++工程名,也可以改成其他的名字,imageProcess()是封装的图像处理方法。


源码:

package trans;


public class GrainCutDll 
{
	static{
		//System.load("D:/Program Files/vs2010project/graduation_project/GrainCutDll/x64/DebugGrainCutDll.dll");
		//System.out.println( System.getProperty("java.library.path") ); 
		System.loadLibrary("GrainCutDll"); //调用的C++的.dll文件
	}
    public native static int imageProcess(String path); //调用的C++方法 
	     


}
2).class和.h文件

按照简单JNI示例:https://blog.csdn.net/xitie8523/article/details/79926948中的方法生成两个文件。

3)vs2013新建工程

打开vs2013,文件——>新建——>项目——>选择win32控制台程序(或者win32项目都可)——>改名称——>确定



点击下一步,选中Dll和空项目,然后完成

4、生成Dll文件

将trans_GrainCutDll.h作为头文件添加到工程里面,新建GrainCutDll.cpp源文件,并将jni.h和jni_md.h作为外部依赖文件导入工程,具体如下:

打开属性管理器——>右击——>点击属性——>转到VC++/常规/附加包含目录 ——>添加文件夹,这里我是把两个.h文件新建一个external_h(随便起的名)文件夹,然后将这个文件夹添加到附加包含目录里



生成的trans_GrainCutDll.h文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class trans_GrainCutDll */

#ifndef _Included_trans_GrainCutDll
#define _Included_trans_GrainCutDll
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     trans_GrainCutDll
 * Method:    imageProcess
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_trans_GrainCutDll_imageProcess
  (JNIEnv *, jclass, jstring);

#ifdef __cplusplus
}
#endif
#endif
GrainCutDll .cpp源文件与一般的C++程序不同的是没有main函数。我在写的时候是直接把我原来的C++程序中imageProcess方法换了个方法名(按.h文件),直接copy过来,而原来工程里面的main就不要了。要记得图像处理函数包含的.h文件依旧要包含,另外还要包含trans_GrainCutDll.h和jni.h与jni_md.h。最后生成就好了,我的vs2013的环境是配置好了的。将生成的dll文件拷贝至jdk下jre的bin目录,其他目录也是可以的。

5)在服务器调用
在服务器中调用之前,我先试了下在java application中能否运行,和前面的简单示例一样的方法。
在其中遇到了一个脑残的问题,我用imread读取图像一直读取不到,返回值为0,当时心里慌呀,认为该不会是java和c++的数据的问题不能直接用C++的函数读取而是要java读取图片然后传到C++程序中进行图像处理吧。后来发现问题在于我vs是debug模式下,但是在配置oencv时没有改过来,用的还是release的lib。此时从编程到生成解决方案,C++都不提个醒。

在tomcat调用依旧是将dll放在jdk下jre的bin目录,没有另外将路径添加到native library location中。在public void doPost(HttpServletRequest request, HttpServletResponse response)方法中,拿到安卓客户端传来的图片后就调用c++方法,如下的grainCut函数。

//对上传的图片进行分割
	public static int grainCut(String srcPath){
		int total = GrainCutDll.imageProcess(srcPath);
		return total;
	} 

打开server,用手机app上传图像,得到结果:

    

总结:

在服务器调用C++程序时,遇到一个问题:客户端发出请求,本来在服务器的函数里面是要返回路径和分割计数的,但是调试时发现运行到调用c++程序那块代码时,直接跳过了,没有报出错信息,也没有异常抛出,最后还上传了图片并返回了路径。百思不得其解。

我后面将本地lib路径添加到native library location后,加载dll,才能够加载dll。最后我还是把native library location去掉了,直接把dll放在jre的bin下面实现的。

另外啰嗦几句,无法加载library和调用不了本地方法是最常见的错误,一般是考虑路径和生成的.h文件,dll文件的问题。

加载绝对路径下的dll:

System.load("D:/Program Files/vs2010project/graduation_project/GrainCutDll/x64/DebugGrainCutDll.dll");

输出dll可以放的位置,一般是jdk的bin,jdk下jre的bin,Tomcat的话就是tomcat的bin,还有说startup.bat所在的目录

System.out.println( System.getProperty("java.library.path") );

猜你喜欢

转载自blog.csdn.net/xitie8523/article/details/80314960