二、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项目都可)——>改名称——>确定
4、生成Dll文件
将trans_GrainCutDll.h作为头文件添加到工程里面,新建GrainCutDll.cpp源文件,并将jni.h和jni_md.h作为外部依赖文件导入工程,具体如下:
打开属性管理器——>右击——>点击属性——>转到VC++/常规/附加包含目录 ——>添加文件夹,这里我是把两个.h文件新建一个external_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)在服务器调用
在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") );