Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

A Simple Way to Create Word Documents by Template in Java under Windows Platform

4.75/5 (4 votes)
2 Dec 2010CPOL3 min read 34K   328  
Using JNI and COM technology generate Word documents in Java under Windows platform

Introduction

There are some open source projects which can create Word documents in Java, like Apache poi, itext, etc. But using COM is a simple way to create Word documents in Java under Windows platform. So I will show you how to use JNI technology to call Windows COM in this article.

Setup Development Environment

  1. Download the latest version of Eclipse from http://www.eclipse.org, and extract compressed file into C:\Eclipse.
  2. Download the latest version of Code::Blocks from http://www.codeblocks.org, and install it into C:\CodeBlocks.
  3. Download the latest version of vole from http://sourceforge.net/projects/vole, which is a neat C++ COM/Automation driver, we can use it to create Word documents easily. And vole depends on the STLSoft libraries, so we need download STLSoft - http://stlsoft.org, too.
  4. Extract file vole-0.7.2.zip into C:\vole-0.7.2, and copy directory “vole” into C:\CodeBlocks\MinGW\include in C:\vole-0.7.2\include.
  5. Extract file stlsoft-1.9.100-hdrs.zip into C:\stlsoft-1.9.100-hdrs, and copy all directories into C:\CodeBlocks\MinGW\include in C:\stlsoft-1.9.100-hdrs\include.

Program Development

  1. Create a new Java project zzutils in Eclipse, and create a new class named Utils, package name is org.zerozone.util. We will define a native method named generateWordDocument, which holds 5 parameters. The method definition is listed below:
    C#
    public static native void generateWordDocument(String fileName,
      String[] bookmarkNames, int bookmarkCount, String[] values,
      int valueCount);
    

    The parameters description:

    • fileName, the file which saves process result
    • bookmarkNames, an array which hold bookmarks what you want to insert into
    • bookmarkCount, a number which indicates how many bookmarks will be processed
    • values, an array which holds values that will be inserted into the right bookmark
    • valueCount, a number which indicates how many values will be inserted
  2. Generate C++ header file with javah which is a tool in jdk. Create a batch file named generate_header.bat, the contents of which are listed below:
    "C:\Program Files\Java\jdk1.6.0_10\bin\javah" 
    -classpath .;./bin org.zerozone.util.Utils

    Run this bat file, then we can get a C++ header file named org_zerozone_util_Utils.h under zztuils project directory.

  3. Create a new dynamic library project named zzutils in Code::Blocks.
    First, copy header file org_zerozone_util_Utils.h into project directory, and add this header file into project, then create a new CPP file named utils.cpp, the contents of which are listed below:
    C++
    #include <windows.h>
    #include "org_zerozone_utils_Utils.h"
    #include "cn_net_ynst_kjjl_util_Utils.h"
    #include <vole/vole.hpp>
    #include <comstl/util/initialisers.hpp>
    using vole::object;
    using vole::collection;
    char* jstringToWindows(JNIEnv *env, jstring jstr)
    {
        int length = env->GetStringLength(jstr);
        const jchar* jcstr = env->GetStringChars(jstr, 0);
        char* rtn = (char*)malloc(length*2+1);
        int size = 0;
        size = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)jcstr, length, 
    			rtn,(length*2+1), NULL, NULL);
        if(size <= 0)
        {
            free(rtn);
            rtn = NULL;
            return NULL;
        }
        env->ReleaseStringChars(jstr, jcstr);
        rtn[size] = 0;
        return rtn;
    }
    jstring windowsToJstring(JNIEnv* env, char* str)
    {
        jstring rtn = 0;
        int slen = strlen(str);
        unsigned short* buffer = 0;
        if(slen == 0)
        {
           rtn = env->NewStringUTF(str);
        }
        else
        {
            int length = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str, slen, NULL, 0);
            buffer = (unsigned short*)malloc(length*2 + 1);
            if( MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str, 
    			slen, (LPWSTR)buffer, length ) > 0)
              rtn = env->NewString((jchar*)buffer, length);
            }
            if(buffer)
            {
              free(buffer);
              buffer = NULL;
            }
            return rtn;
        }
    }
    JNIEXPORT void JNICALL Java_cn_net_ynst_kjjl_util_Utils_generateWordDocument
        (JNIEnv *env, jclass clazz, jstring fileName, jobjectArray bookmarkNames,
         jint bookmarkCount, jobjectArray values, jint valueCount)
    {
        if(bookmarkCount != valueCount)
            return;
        int len = 0;
        char* _fileName = jstringToWindows(env, fileName);
        len = MultiByteToWideChar(CP_ACP, 0, 
    	(LPCSTR)_fileName, strlen(_fileName) + 1, NULL, 0);
        wchar_t* _w_fileName = new wchar_t[len];
        MultiByteToWideChar(CP_ACP, 0, (LPCSTR)_fileName, -1, _w_fileName, len);
        comstl::com_init init;
        object word = object::create("Word.Application", CLSCTX_LOCAL_SERVER,
        vole::coercion_level::naturalPromotion);
        word.put_property(L"Visible", false);
        collection documents = word.get_property<collection>(L"Documents");
        object document = documents.invoke_method<object>
    			(L"Open", (LPCWSTR)_w_fileName);
        collection bookmarks = document.get_property<collection>(L"Bookmarks");
        int count = bookmarks.get_property<int>(L"Count");
        for(int i = 1; i <= count; i++)
        {
            object bookmark = bookmarks.invoke_method<object>(L"Item", i);
            std::string name = bookmark.get_property<std::string>(L"Name");
            for(int j = 0; j < bookmarkCount; j++)
            {
                jstring bookmarkName = 
    		(jstring)env->GetObjectArrayElement(bookmarkNames, j);
                const char* _bookmarkName = env->GetStringUTFChars(bookmarkName, 0);
                if(strcmp(name.c_str(), _bookmarkName) == 0)
                {
                    jstring value = (jstring)env->GetObjectArrayElement(values, j);
                    char* _value = jstringToWindows(env, value);
                    len = MultiByteToWideChar(CP_ACP, 0, 
    			(LPCSTR)_value, strlen(_value) + 1, NULL, 0);
                    wchar_t* _w_value = new wchar_t[len];
                    MultiByteToWideChar(CP_ACP, 0, (LPCSTR)_value, -1, _w_value, len);
                    object range = bookmark.get_property<object>(L"Range");
                    range.invoke_method_v(L"InsertAfter", (LPCWSTR)_w_value);
                    free(_value);
                    free(_w_value);
                    _value = NULL;
                    _w_value = NULL;
                    env->ReleaseStringUTFChars(bookmarkName, _bookmarkName);
                    break;
                }
                env->ReleaseStringUTFChars(bookmarkName, _bookmarkName);
            }
        }
        document.invoke_method_v(L"Save");
        document.invoke_method_v(L"Close", false);
        word.invoke_method_v(L"Quit");
        free(_fileName);
        free(_w_fileName);
    }
  4. Create a new Word document in Word, and insert two bookmarks named title and year, save it and name it as 1.doc, path is C:\. We will use it as a template file.

When all the above steps have been completed, we can compile it in Code::Blocks, and get a file named zztuils.dll, please copy this file into project zzutils which is created by eclipse. Then we could run main method in class Utils.

Advantages & Shortcomings

Advantages

  1. We can use features of COM technology to create Word document easily.
  2. We can code less than what projects which use apache poi or something else do.

Shortcomings

  1. This program can run under Windows platform only.
  2. Deploy it into tomcat and it could be crashed when called 5-6 times. I will try web service way to avoid this problem.

History

  • 2nd December, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)