2013-11-03 28 views
10

Tôi chỉ mới bắt đầu xây dựng các ứng dụng Java (Tôi có trải nghiệm .NET) và tôi đang cố gắng xây dựng một ứng dụng thử nghiệm nhỏ có toàn bộ mã này:ClassNotFoundException khi chạy JAR, không có lỗi khi chạy trong IntelliJ IDEA

package com.company; 

import com.microsoft.sqlserver.jdbc.SQLServerDataSource; 

import java.sql.Connection; 
import java.sql.PreparedStatement; 
import java.sql.ResultSet; 
import java.sql.SQLException; 

public class Main { 

    public static void main(String[] args) throws SQLException { 
     System.out.println("Buna lume!"); 

     SQLServerDataSource ds = new SQLServerDataSource(); 
     ds.setIntegratedSecurity(true); 
     ds.setServerName("localhost"); 
     ds.setPortNumber(1433); 
     ds.setDatabaseName("Test"); 
     Connection con = ds.getConnection(); 

     String SQL = "SELECT * FROM Test WHERE ID = ?"; 
     PreparedStatement stmt = con.prepareStatement(SQL); 
     stmt.setInt(1, 2); 
     ResultSet rs = stmt.executeQuery(); 

     while (rs.next()) { 
      System.out.println(rs.getInt(1) + ", " + rs.getString(2)); 
     } 
     rs.close(); 
     stmt.close(); 

     con.close(); 
    } 
} 

Nếu tôi chạy ứng dụng trong IDE (IntelliJ IDEA 12.1.6 Community Edition), có SQL Server khả dụng, ứng dụng chạy tốt làm chính xác những gì cần.

Trình điều khiển máy chủ SQL được tải xuống từ Microsoft và được thêm làm Thư viện bên ngoài. Tôi đã tạo ra một artifact như tập tin JAR:

enter image description here

Bây giờ, nếu tôi bao gồm các sqljdbc4.jar trong cliTest.jar (JAR của tôi) JAR dẫn là chất béo (550kB và bao gồm các lớp trong JAR quá). Hoặc tôi có thể loại trừ nó. Dù bằng cách nào, chạy

java -jar cliTest.jar 

Kết quả trong

Buna lume! 
Exception in thread "main" java.lang.NoClassDefFoundError: com/microsoft/sqlserv 
er/jdbc/SQLServerDataSource 
     at com.company.Main.main(Main.java:15) 
Caused by: java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLSer 
verDataSource 
     at java.net.URLClassLoader$1.run(Unknown Source) 
     at java.net.URLClassLoader$1.run(Unknown Source) 
     at java.security.AccessController.doPrivileged(Native Method) 
     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) 
     ... 1 more 

Tôi đặt cược tôi là thiếu một cái gì đó khá cơ bản nhưng tôi chỉ không thể tìm ra chính xác những gì đang gây ra này.

LE1: Tôi đã thử thêm sqljdbc4.jar (mặc dù nó không có vẻ cần thiết) và sqljdbc_auth.dll trong thư mục chứa JAR nhưng vẫn không thay đổi.

Sau đó chỉnh sửa 2: Dựa trên câu trả lời Nikolay của tôi đã thực hiện như sau:

  1. Deleted artifact hiện
  2. Tạo một artifact mới như vậy:

enter image description here

enter image description here

.. a nd dẫn này:

enter image description here

  1. Build -> Build hiện vật -> cliTest.jar -> Rebuild

  2. CMD Prompt tại thư mục chứa:

[cliTest.jar 566 KB được tạo]

java -jar cliTest.jar

Bây giờ tôi nhận được:

Exception in thread "main" java.lang.SecurityException: Invalid signature file d 
igest for Manifest main attributes 
    at sun.security.util.SignatureFileVerifier.processImpl(Unknown Source) 
    at sun.security.util.SignatureFileVerifier.process(Unknown Source) 
    at java.util.jar.JarVerifier.processEntry(Unknown Source) 
    at java.util.jar.JarVerifier.update(Unknown Source) 
    at java.util.jar.JarFile.initializeVerifier(Unknown Source) 
    at java.util.jar.JarFile.getInputStream(Unknown Source) 
    at sun.misc.URLClassPath$JarLoader$2.getInputStream(Unknown Source) 
    at sun.misc.Resource.cachedInputStream(Unknown Source) 
    at sun.misc.Resource.getByteBuffer(Unknown Source) 
    at java.net.URLClassLoader.defineClass(Unknown Source) 
    at java.net.URLClassLoader.access$100(Unknown Source) 
    at java.net.URLClassLoader$1.run(Unknown Source) 
    at java.net.URLClassLoader$1.run(Unknown Source) 
    at java.security.AccessController.doPrivileged(Native Method) 
    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) 
    at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source) 

Trả lời

3

Tôi cũng nên xây dựng JAR mà không cần chèn sqljdbc4.jar.

Điều thứ hai tôi phải chạy lệnh như vậy:

java -classpath sqljdbc4.jar;cliTest.jar com.company.Main 

.. và sau đó tất cả đã làm việc!

+0

Đây là một cách. Nhưng việc nhúng mọi tập tin lớp vào một cái bình cũng sẽ hoạt động. Lưu ý rằng tệp jar thực sự là tệp zip, vì vậy bạn luôn có thể mở chúng và xem bên trong để xem liệu chúng có chứa tất cả các lớp hay không. – lbalazscs

+0

Có, tôi đã nhìn trộm trong JAR phụ thuộc (sqljdbc4.jar) nhưng cố gắng để đẩy nó vào kết quả JAR của tôi sẽ mang lại SecurityException như trong phần cuối của câu hỏi. Tôi đoán JAR đã được nhúng đã được ký kết và bao gồm một không ... hoặc một cái gì đó như thế. –

+0

Có, nếu bạn nhúng tất cả các tệp của một lọ đã ký vào một cái lọ lớn, chữ ký có thể gây ra vấn đề. Bạn có thể xóa các tệp RSA META-INF/*. SF, META-INF/*. DSA và META-INF/* .Để loại bỏ chữ ký. – lbalazscs

4

Sử dụng java -cp thay vì java -jar và đặt tất cả các bạn cách phụ thuộc lọ vào classpath.

Một cách khác là gói tất cả các phụ thuộc vào một bình, cho phép bạn chạy ứng dụng bằng cách sử dụng java -jar.

EDIT:

Trong Java * file .jar chứa một số lượng lớn của các tầng lớp. Khi bạn xây dựng ứng dụng của riêng mình, thông thường, tệp jar kết quả chỉ chứa các lớp của bạn, nhưng vẫn phải tải các lớp từ các thư viện bên ngoài mà bạn sử dụng (được gọi là các phụ thuộc).

Nó có thể được thực hiện hai cách khác nhau:

  1. Bạn tạo một thư mục cho ứng dụng của bạn, ví dụ, gọi lib và đặt jar ứng dụng của bạn và tất cả phụ thuộc vào. Sau đó, bạn chạy ứng dụng sử dụng java -cp lib:/\* com.company.Main hoặc (nhờ @NilsH, tôi bỏ lỡ phiên bản này) bạn thực hiện MANIFEST.MF tập tin và chỉ định Main-ClassClasspath thuộc tính bên trong như đã mô tả here

  2. Bạn sử dụng công cụ đặc biệt (như maven-phụ thuộc-plugin nếu bạn sử dụng maven cho xây dựng) để đóng gói tất cả các lớp học, hoặc của riêng bạn, hoặc là bên ngoài để jar duy nhất. Bạn có một tệp lớn và có thể chạy tệp này bằng cách sử dụng java -jar cliTest.jar.

Nói chung, cách tiếp cận đầu tiên được ưu tiên và sử dụng tệp MANIFEST.MF là một hình thức tốt.

+0

Ok, nhưng tôi vẫn xây dựng JAR hay không? –

+0

Có, tôi đã giải thích câu trả lời của tôi. – Nikolay

+0

Tôi phải không đồng ý. Cách "thích hợp" để xây dựng một jar thực thi là có tệp MANIFEST.MF thích hợp trong thư mục META-INF của tệp jar và chạy nó bằng 'java -jar'. Tệp 'MANIFEST.MF' phải chứa các mục nhập cho các jars phụ thuộc trong phần' Class-Path', ngoài thuộc tính 'Main-Class' của tệp kê khai. – NilsH

-1

Vâng, nếu bạn đang sử dụng maven, bạn có thể sử dụng maven-shade-plugin để bao gồm jar phụ thuộc trong jar thực thi, đoạn mã của tệp pom.xml được đưa ra dưới đây.

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-shade-plugin</artifactId> 
       <version>2.4.3</version> 
       <executions> 
        <execution> 
         <phase>package</phase> 
         <goals> 
          <goal>shade</goal> 
         </goals> 
         <configuration> 
          <transformers> 
           <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">          <mainClass>com.main.class.YouMainClass</mainClass> 
           </transformer> 
          </transformers> 
          <filters> 
           <filter> 
            <artifact>*:*</artifact> 
            <excludes> 
             <exclude>META-INF/*.SF</exclude> 
             <exclude>META-INF/*.DSA</exclude> 
             <exclude>META-INF/*.RSA</exclude> 
            </excludes> 
           </filter> 
          </filters> 
         </configuration> 
        </execution> 
       </executions> 
      </plugin> 
Các vấn đề liên quan