Làm cách nào để thiết lập Ứng dụng JAX-RS chỉ sử dụng chú thích (không có web.xml)?


80

Có thể thiết lập ứng dụng JAX-RS chỉ bằng chú thích không? (sử dụng Servlet 3.0 và JAX-RS Jersey 1.1.0)

Tôi đã thử và không có may mắn. Sử dụng một số web.xmlcó vẻ cần thiết.


Cấu hình A (hoạt động, nhưng có cấu hình web.xml)

web.xml

   ...
   <servlet>
      <servlet-name>org.foo.rest.MyApplication</servlet-name>
   </servlet>
   <servlet-mapping>
       <servlet-name>org.foo.rest.MyApplication</servlet-name>
       <url-pattern>/*</url-pattern>
   </servlet-mapping>
   ...

Java

@ApplicationPath("/")
public class MyApplication extends Application {
    ...
}

Cấu hình B (không hoạt động, ngoại lệ được ném)

@ApplicationPath("/")
@WebServlet("/*") // <-- 
public class MyApplication extends Application {
    ...
}

Sau này dường như nhấn mạnh rằng Ứng dụng sẽ là một lớp con của Servlet (ngoại lệ không để lại phỏng đoán)

java.lang.ClassCastException: org.foo.rest.MyApplication cannot be cast to javax.servlet.Servlet

Câu hỏi

  1. Tại sao định nghĩa web.xml hoạt động nhưng chú thích thì không? Có gì khác biệt?

  2. Có cách nào để nó hoạt động, ví dụ: có Ứng dụng JAX-RS không có web.xml không?


1
Nếu bạn có thể thử với NetBeans, có một trình hướng dẫn để tạo dịch vụ web RESTFul. Có vẻ như những gì bạn đang cố gắng làm là những gì thuật sĩ này làm trong phiên bản 6.8. Tôi đang sử dụng 7.0.1 và cách tiếp cận mới là đơn giản nhưng sử dụng một servlet duy nhất cho mục đích này, đó là com.sun.jersey.spi.container.servlet.ServletContainer nhưng nó được định nghĩa trong web.xml
perissf

Câu trả lời:


168

** VUI LÒNG ĐỌC NẾU BẠN SỬ DỤNG TOMCAT HOẶC JETTY! **

Câu trả lời được chấp nhận sẽ hoạt động, nhưng chỉ khi ứng dụng web được triển khai tới máy chủ ứng dụng như Glassfish hoặc Wildfly và có thể là vùng chứa servlet có phần mở rộng EE như TomEE. Nó không hoạt động trên các thùng chứa servlet tiêu chuẩn như Tomcat, mà tôi chắc rằng hầu hết mọi người đang tìm kiếm giải pháp ở đây đều muốn sử dụng.

Nếu bạn đang sử dụng bản cài đặt Tomcat tiêu chuẩn (hoặc một số vùng chứa servlet khác), bạn cần bao gồm triển khai REST vì Tomcat không đi kèm với một bản cài đặt. Nếu bạn đang sử dụng Maven, hãy thêm phần này vào dependenciesphần:

<dependencies>
  <dependency>
    <groupId>org.glassfish.jersey.bundles</groupId>
    <artifactId>jaxrs-ri</artifactId>
    <version>2.13</version>
  </dependency>
  ...
</dependencies>

Sau đó, chỉ cần thêm một lớp cấu hình ứng dụng vào dự án của bạn. Nếu bạn không có bất kỳ nhu cầu cấu hình đặc biệt nào ngoài việc thiết lập đường dẫn ngữ cảnh cho các dịch vụ còn lại, thì lớp có thể trống. Khi lớp này được thêm vào, bạn không cần phải định cấu hình bất kỳ thứ gì trong web.xml(hoặc có một cái gì cả):

package com.domain.mypackage;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("rest") // set the path to REST web services
public class ApplicationConfig extends Application {}

Sau đó, việc khai báo các dịch vụ web của bạn sẽ được thực hiện ngay bằng cách sử dụng các chú thích JAX-RS tiêu chuẩn trong các lớp Java của bạn:

package com.domain.mypackage;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.Path;

// It's good practice to include a version number in the path so you can have
// multiple versions deployed at once. That way consumers don't need to upgrade
// right away if things are working for them.
@Path("calc/1.0")
public class CalculatorV1_0 {
  @GET
  @Consumes("text/plain")
  @Produces("text/plain")
  @Path("addTwoNumbers")
  public String add(@MatrixParam("firstNumber") int n1, @MatrixParam("secondNumber") int n2) {
    return String.valueOf(n1 + n2);
  }
}

Đây là tất cả những gì bạn cần. Nếu cài đặt Tomcat của bạn đang chạy cục bộ trên cổng 8080 và bạn triển khai tệp WAR của mình vào ngữ cảnh myContext, đi tới ...

http://localhost:8080/myContext/rest/calc/1.0/addTwoNumbers;firstNumber=2;secondNumber=3

... nên tạo ra kết quả mong đợi (5).


6
@JavaDude - Bạn phải định cấu hình Maven để tạo tệp WAR ngay cả khi tệp web.xmlnày không có. Trong bạn pom.xml, trong phần "xây dựng> plugins", add (nếu chưa có): <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-war-plugin</artifactId><version>2.3</version><configuration><failOnMissingWebXml>false</failOnMissingWebXml></configuration></plugin>.
Alvin Thompson

6
@JavaDude - phần quan trọng là <failOnMissingWebXml>false</fai‌​lOnMissingWebXml>tùy chọn.
Alvin Thompson

3
@JavaDude - Nếu không phải vậy, có thể bạn đã không tạo một lớp mở rộng Applicationvà thêm @ApplicationPathchú thích vào nó. Lớp có thể trống, nhưng nó phải ở đó.
Alvin Thompson

3
Chỉ thêm vào là đủ jersey-container-servletmà không cần kéo toàn bộ jaxrs-risự phụ thuộc. Ví dụ: trong trường hợp của tôi, nó là 'org.glassfish.jersey.core:jersey-server:2.18'+ 'org.glassfish.jersey.containers:jersey-container-servlet:2.18'.
leveluptor

3
Vì câu hỏi được gắn thẻ rõ ràng là "java-ee", tôi không hiểu rõ ràng về việc cung cấp và ủng hộ câu trả lời KHÔNG đề cập đến môi trường jee. -1
Jan Galinski

51

Có vẻ như tất cả những gì tôi cần làm là điều này (Servlet 3.0 trở lên)

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/*")
public class MyApplication extends Application {
    ...
}

Và dường như không cần cấu hình web.xml (đã thử trên Tomcat 7)


1
Không hiểu cách này hoạt động như thế nào, bạn chỉ có thể sử dụng chú thích mà không có bất kỳ cấu hình nào khác? Tôi đã cố gắng như thế này mà vẫn không làm việc ...
Filipe

2
@Filipe: Tôi đoán rằng bạn đang sử dụng Tomcat hoặc một số vùng chứa servlet khác. Điều này thực sự không hoạt động trên các thùng chứa servlet như Tomcat - nó chỉ hoạt động với các máy chủ ứng dụng như Glassfish hoặc Wildfly và có thể là TomEE. Nếu bạn đang sử dụng Tomcat, hãy xem câu trả lời (muộn) của tôi bên dưới.
Alvin Thompson

8
Câu trả lời này KHÔNG hoạt động với Tomcat hoặc Jetty! Vui lòng xem câu trả lời của tôi để biết mọi thứ hoạt động trong các thùng chứa servlet đó (và các vùng khác).
Alvin Thompson

1
Tùy theo tình hình thực hiện, bạn làm cần một web.xml, mặc dù là một sản phẩm nào sẽ đủ. Xem docs.jboss.org/resteasy/docs/3.0.9.Final/userguide/html_single/…
Benjamin Maurer

Điều này hoạt động trên WebSphere Liberty nhưng không hoạt động trên WebSphere 8.x và 9.0 Classic.
Archimedes Trajano

15

Chương 2 của đặc tả JAX-RS: Java ™ API cho RESTful Web Services mô tả quy trình xuất bản của ứng dụng JAX-RS trong môi trường Servlet (phần 2.3.2 Servlet trong đặc tả).

Xin lưu ý rằng môi trường Servlet 3 chỉ được khuyến nghị (phần 2.3.2 Servlet, trang 6):

KHUYẾN CÁO rằng việc triển khai hỗ trợ cơ chế cắm thêm của khung Servlet 3 để cho phép khả năng di chuyển giữa các vùng chứa và tận dụng các phương tiện quét lớp do vùng chứa cung cấp.

Tóm lại, nếu bạn muốn sử dụng phương pháp tiếp cận no-web.xml, bạn có thể triển khai tùy chỉnh javax.ws.rs.core.Application đăng ký tài nguyên dịch vụ RESTful với chú thích javax.ws.rs.ApplicationPath .

@ApplicationPath("/rest")

Mặc dù bạn đã hỏi cụ thể về Jersey, bạn cũng có thể muốn đọc bài viết Triển khai các dịch vụ RESTful với JAX-RS và WebSphere 8.5 Liberty Profile, trong đó tôi đã mô tả quy trình xuất bản no-web.xml cho WebSphere Liberty Profile (với Apache Wink là việc triển khai JAX-RS).


1
Cảm ơn !, Tôi có một câu hỏi khác có liên quan mạnh mẽ đang khiến tôi phát điên, có cách nào để có đường dẫn trong thư mục gốc (ví dụ: @ApplicationPath ("/ *")) và vẫn chỉ phục vụ JSP bằng cách sử dụng Annotations không? (mặc dù ngay cả với cấu hình web.xml, tôi không thể làm điều đó xảy ra) - câu hỏi ở đây: stackoverflow.com/questions/10874188/… , vì bạn có vẻ biết khá rõ về JAX-RS, bạn có vui lòng xem qua không? :) có lẽ bạn sẽ thấy những gì tôi đang thiếu ... cảm ơn!
Eran Medan

Tôi không biết. Gut cảm nhận cho tôi biết rằng nó sẽ hoạt động mà không cần cấu hình bổ sung vì quá trình phân giải tài nguyên để xử lý một yêu cầu là từ đối sánh chính xác với các mẫu URL. Tôi sẽ xem xét và trả lời. Cảm ơn vì đã khuyến khích tôi mở mang kiến ​​thức! :-)
Jacek Laskowski

Tôi đang sử dụng @ApplicationPath("")để có các dịch vụ REST của mình trong thư mục gốc (liên quan đến gốc ngữ cảnh ứng dụng web) trên JBoss EAP 7. Tôi beans.xmlcũng không có web.xml.
Julien Kronegg

7

Bạn cần thiết lập các phụ thuộc phù hợp trong pom.xml

<dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.0.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
    </dependency>

Thêm chi tiết tại đây: Ví dụ người mới bắt đầu cho jax-rs


tôi có thể xóa web.xml nếu sử dụng ResourceConfig / Application không?
BAE

vâng, nhưng bạn cần phải thêm này trong pom.xml i fusnig Mave:<failOnMissingWebXml>
ACV

cảm ơn. nhưng có điều gì web.xml có thể làm nhưng ResourceConfig không thể?
BAE

Không, tôi nghĩ vì web.xml của servlet spec 3.0 không còn cần thiết nữa. Nhưng đôi khi sử dụng web.xml sẽ thuận tiện hơn vì nó không yêu cầu biên dịch lại nếu bạn muốn thay đổi điều gì đó.
ACV

Và nếu bạn không sử dụng Maven thì sao? Dự án của tôi hiện quá lớn để chuyển lại.
TheRealChx101

1

Các phụ thuộc được đề cập trước đó không hoạt động đối với tôi. Từ Hướng dẫn sử dụng Jersey:

Jersey cung cấp hai mô-đun Servlet. Mô-đun đầu tiên là mô-đun Servlet lõi Jersey cung cấp hỗ trợ tích hợp Servlet cốt lõi và được yêu cầu trong bất kỳ vùng chứa Servlet 2.5 hoặc cao hơn nào:

<dependency>
 <groupId>org.glassfish.jersey.containers</groupId>
 <artifactId>jersey-container-servlet-core</artifactId>
</dependency>

Để hỗ trợ các chế độ triển khai Servlet 3.x bổ sung và mô hình lập trình tài nguyên JAX-RS không đồng bộ, cần có thêm mô-đun Jersey:

<dependency>
 <groupId>org.glassfish.jersey.containers</groupId>
 <artifactId>jersey-container-servlet</artifactId>
</dependency>

Mô-đun jersey-container-servlet phụ thuộc vào mô-đun lõi jersey-container-servlet-core, do đó khi nó được sử dụng, không cần khai báo rõ ràng sự phụ thuộc jersey-container-servlet-core.

https://jersey.github.io/documentation/latest/deployment.html#deployment.servlet.3


0

Như @ Eran-Medan đã chỉ ra, JBoss EAP 7.1 (lưu ý rằng không có Ứng dụng web nên không có servlet, tôi đang thực hiện nó trong một dự án EJB 3.2), tôi phải thêm thuộc tính "value" chẳng hạn như tôi đã nhận được một ngoại lệ thuộc tính giá trị là bắt buộc.

Điều này đã làm việc cho tôi

    @ApplicationPath(value="/*")
        public class MyApplication extends Application {

            private Set singletons = new HashSet();

            public MyApplication() {
                singletons.add(new MyService());
            }

            ...
    }

Dấu vết ngăn xếp

    Caused by: java.lang.annotation.IncompleteAnnotationException: javax.ws.rs.ApplicationPath missing element value
        at sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:80)
        at com.sun.proxy.$Proxy141.value(Unknown Source)
        ... 21 more
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.