简体   繁体   English

在Maven项目中使用Apache POI运行.jar文件

[英]Running .jar file using Apache POI in Maven project

I'm struggling to run a simple program that uses Apache POI to create an Excel document. 我正在努力运行一个使用Apache POI创建Excel文档的简单程序。 This is also my first time with a Maven project, so that might have something to do with it: 这也是我第一次参与Maven项目,因此可能与它有关:

My pom.xml looks like this: 我的pom.xml看起来像这样:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany.app</groupId>
  <artifactId>calendar</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>calendar</name>
  <url>http://maven.apache.org</url>

    <dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>

    <dependency>
          <groupId>org.apache.poi</groupId>
          <artifactId>poi</artifactId>
          <version>3.10-FINAL</version>
    </dependency>


    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>3.10-FINAL</version>
    </dependency>

  </dependencies>
</project>

From what I can tell, my dependencies are alright. 据我所知,我的依赖关系还不错。

This is my java code, I skipped over import statements but they are all there, no errors in this code from what I can tell: 这是我的Java代码,我跳过了import语句,但是它们都在那里,根据我的判断,此代码中没有错误:

public class App 
{

    private static final String FILE_NAME = "/tmp/MyFirstExcel.xlsx";

    public static void main( String[] args ) throws IOException
    {
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet("Datatypes in Java");

        Object[][] datatypes = {
            {"Datatype", "Type", "Size(in bytes)"},
            {"int", "Primitive", 2},
            {"float", "Primitive", 4},
            {"double", "Primitive", 8},
            {"char", "Primitive", 1},
            {"String", "Non-Primitive", "No fixed size"}    
        };

        int rowNum = 0;
        System.out.println("Creating excel");
        for(Object[] datatype : datatypes) {
            Row row = sheet.createRow(rowNum++);
            int colNum = 0;
            for(Object field : datatype) {
                Cell cell = row.createCell(colNum++);
                if(field instanceof String) {
                    cell.setCellValue((String) field);
                }
                else if(field instanceof Integer) {
                    cell.setCellValue((Integer) field);
                }
            }
        }

        try {
            FileOutputStream outputStream = new FileOutputStream(FILE_NAME);
            workbook.write(outputStream);
            //workbook.close()
        } catch (FileNotFoundException e) {
            System.out.println("Couldn't find file to write out to");
        } catch (IOException e) {
            System.out.println("IO Exception in printing");
        }

    }
}

I have workbook.close() commented out since this caused an error (deprecated method?). 我已经注释掉了workbook.close() ,因为这导致了错误(不建议使用的方法?)。

With the above code in my source folder, I can run mvn package which builds successfully and generates the .jar file calendar-1.0-SNAPSHOT.jar in the target folder. 使用上面的代码在我的源文件夹中,我可以运行mvn package ,该mvn package可以成功构建并在目标文件夹中生成.jar文件calendar-1.0-SNAPSHOT.jar

I am attempting to run this file using 我正在尝试使用运行此文件

java -cp target/calendar-1.0-SNAPSHOT.jar com.mycompany.app.App

...and I get the following error message ...并且我收到以下错误消息

Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/poi/ss/usermodel/Workbook
        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
        at java.lang.Class.privateGetMethodRecursive(Unknown Source)
        at java.lang.Class.getMethod0(Unknown Source)
        at java.lang.Class.getMethod(Unknown Source)
        at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
        at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
Caused by: java.lang.ClassNotFoundException: org.apache.poi.ss.usermodel.Workbook
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 7 more

If this question requires any more information let me know. 如果这个问题需要更多信息,请告诉我。 I'm at a loss here. 我在这里茫然。

You need to create a fat/uber jar with Maven Assembly Plugin. 您需要使用Maven Assembly Plugin创建一个胖子/超级瓶子。 Which means create a Jar together with its dependency Jars into a single executable Jar file. 这意味着将一个Jar及其依赖的Jar一起创建到一个可执行的Jar文件中。 When you run it then it would have all the dependencies available. 当您运行它时,它将具有所有可用的依赖项。

Add following plugin inside your POM 在您的POM中添加以下插件

<build>
    <plugins>
        <!-- Maven Assembly Plugin -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.4.1</version>
            <configuration>
                <!-- get all project dependencies -->
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <!-- MainClass in mainfest make a executable jar -->
                <archive>
                  <manifest>
                    <mainClass>com.your.path.to.main.App</mainClass>
                  </manifest>
                </archive>

            </configuration>
            <executions>
              <execution>
                <id>make-assembly</id>
                                    <!-- bind to the packaging phase -->
                <phase>package</phase>
                <goals>
                    <goal>single</goal>
                </goals>
              </execution>
            </executions>
        </plugin>

    </plugins>
</build>

Run following: 运行以下命令:

mvn package

Two jar files will be created in the target folder. 将在目标文件夹中创建两个jar文件。

calendar-1.0-SNAPSHOT.jar – Only your project classes
calendar-1.0-SNAPSHOT-with-dependencies.jar – Project and dependency classes in a single jar.

You can run it follwoing; 您可以按照以下方式运行它;

java -cp target/calendar-1.0-SNAPSHOT-with-dependencies.jarcom.mycompany.app.App

You can review the contents of calendar-1.0-SNAPSHOT-with-dependencies.jar 您可以查看calendar-1.0-SNAPSHOT-with-dependencies.jar的内容

jar tf target/calendar-1.0-SNAPSHOT-with-dependencies.jar

You are packaging your maven artifact as a jar and by default a jar packaged by the maven jar plugin doesn't include the dependency jars with the built artifact. 您将maven工件打包为jar,并且默认情况下,由maven jar插件打包的jar不包含带有已构建工件的依赖项jar。 Whereas the missing class at runtime. 而运行时缺少的类。

If you want to include dependency jars of your application inside your jar, you should use the maven assembly plugin and specify jar-with-dependencies for the descriptorRef parameter. 如果要在jar中包含应用程序的依赖jar,则应使用maven程序集插件,并为描述符ref参数指定jar-with-dependencies

You could bind the assembly single goal execution to the package phase so that the mvn package execution that you are using actually creates automatically the expected jar. 您可以将程序集的single目标执行绑定到程序包阶段,以便您正在使用的mvn package执行实际上自动创建预期的jar。

<plugins>
  <plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
      <archive>
        <manifest>
          <mainClass>YourMainClassPrefixedByItsPackage</mainClass>
        </manifest>
      </archive>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
    </configuration>
    <executions>
      <execution>
        <id>make-assembly</id> 
        <phase>package</phase> <!-- bind to the packaging phase -->
        <goals>
          <goal>single</goal>
        </goals>
      </execution>
    </executions>
  </plugin>

The problem is that at compile time POI libraries are available but not at run time. 问题是在编译时POI库可用,但在运行时不可用。 The reason why they are available is that they are in Maven Dependency. 它们可用的原因是它们处于Maven依赖关系中。 Also I don't see any build wrapper in your pom file. 另外,我在pom文件中看不到任何构建包装器。 You will need to add a build wrapper to build jar file that you can run outside of your IDE. 您将需要添加构建包装器来构建可以在IDE外部运行的jar文件。

Now coming back to your problem, either you need to add POI jar in your CLASSPATH environment variable so that java run-time can access it or build a fat jar including dependencies. 现在回到您的问题,您需要在CLASSPATH环境变量中添加POI jar,以便Java运行时可以访问它或构建包含依赖项的胖jar。

You can use this template to add a build wrapper in pom file to build jar with dependencies. 您可以使用此模板在pom文件中添加构建包装器,以构建具有依赖项的jar。

<build>
    <plugins>
      <plugin>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
          <execution>
            <phase>install</phase>
            <goals>
              <goal>copy-dependencies</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.directory}/lib</outputDirectory>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

Maven package task just packs compiled classes of your project into a single jar file. Maven package任务只是将项目的已编译类打包到单个jar文件中。 All 3rd party libraries are not included, that's why you're getting error - POI class is not found. 所有第三方库均未包括在内,这就是为什么您会报错-未找到POI类。

You should build a runnable jar file that includes all dependencies. 您应该构建一个包含所有依赖项的可运行jar文件。 Please, refer to this question - you should use some additional maven plugins to achieve that 请参考这个问题-您应该使用一些其他的Maven插件来实现这一目标

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM