JAX-RS - Làm thế nào để trả lại mã trạng thái JSON và HTTP cùng nhau?


248

Tôi đang viết một ứng dụng web REST (NetBeans 6.9, JAX-RS, TopLink Essentials) và cố gắng trả về mã trạng thái JSON HTTP. Tôi đã sẵn sàng mã và làm việc trả về JSON khi phương thức HTTP GET được gọi từ máy khách. Bản chất:

@Path("get/id")
@GET
@Produces("application/json")
public M_機械 getMachineToUpdate(@PathParam("id") String id) {

    // some code to return JSON ...

    return myJson;
}

Nhưng tôi cũng muốn trả về mã trạng thái HTTP (500, 200, 204, v.v.) cùng với dữ liệu JSON.

Tôi đã cố gắng sử dụng HttpServletResponse:

response.sendError("error message", 500);

Nhưng điều này làm cho trình duyệt nghĩ rằng đó là 500 "thực" nên trang web đầu ra là trang lỗi HTTP 500 thông thường.

Tôi muốn trả về mã trạng thái HTTP để JavaScript phía máy khách của tôi có thể xử lý một số logic tùy thuộc vào nó (ví dụ: hiển thị mã lỗi và thông báo trên trang HTML). Điều này có thể hoặc không nên sử dụng mã trạng thái HTTP cho điều đó?


2
Sự khác biệt giữa 500 bạn muốn (không thật? :)) và 500 thực?
dao cạo

@razor Ở đây thực 500 có nghĩa là một trang lỗi HTML thay vì phản hồi JSON
Nupur

trình duyệt web không được thiết kế để hoạt động với JSON, nhưng với các trang HTML, vì vậy nếu bạn phản hồi với 500 (và thậm chí cả phần thân thông báo), trình duyệt có thể hiển thị cho bạn chỉ là một thông báo lỗi (thực sự phụ thuộc vào việc triển khai trình duyệt), chỉ vì nó hữu ích cho một người dùng bình thường.
dao cạo

Câu trả lời:


347

Đây là một ví dụ:

@GET
@Path("retrieve/{uuid}")
public Response retrieveSomething(@PathParam("uuid") String uuid) {
    if(uuid == null || uuid.trim().length() == 0) {
        return Response.serverError().entity("UUID cannot be blank").build();
    }
    Entity entity = service.getById(uuid);
    if(entity == null) {
        return Response.status(Response.Status.NOT_FOUND).entity("Entity not found for UUID: " + uuid).build();
    }
    String json = //convert entity to json
    return Response.ok(json, MediaType.APPLICATION_JSON).build();
}

Hãy xem lớp Phản hồi .

Lưu ý rằng bạn phải luôn chỉ định một loại nội dung, đặc biệt nếu bạn chuyển nhiều loại nội dung, nhưng nếu mọi thông báo sẽ được biểu diễn dưới dạng JSON, bạn chỉ có thể chú thích phương thức với @Produces("application/json")


12
Nó hoạt động, nhưng điều tôi không thích về giá trị trả về Phản hồi là theo ý kiến ​​của tôi, nó làm ô nhiễm mã của bạn, đặc biệt liên quan đến bất kỳ khách hàng nào đang cố gắng sử dụng nó. Nếu bạn cung cấp giao diện trả về Phản hồi cho bên thứ ba, anh ta không biết bạn thực sự trở về loại nào. Spring làm cho nó rõ ràng hơn với một chú thích, rất hữu ích nếu bạn luôn trả về mã trạng thái (ví dụ HTTP 204)
Guido

19
Làm cho lớp đó chung chung (Phản hồi <T>) sẽ là một cải tiến thú vị cho jax-rs, để có những lợi thế của cả hai lựa chọn thay thế.
Guido

41
Không cần phải chuyển đổi thực thể thành json bằng cách nào đó. Bạn có thể thực hiện return Response.status(Response.Status.Forbidden).entity(myPOJO).build();Công việc như thể bạn return myPOJO;, nhưng với cài đặt bổ sung mã Trạng thái HTTP.
kratenko

1
Tôi nghĩ rằng tách logic kinh doanh ra thành một lớp dịch vụ riêng biệt hoạt động tốt. Điểm cuối sử dụng Phản hồi làm kiểu trả về và các phương thức của nó chủ yếu chỉ là các cuộc gọi đến các phương thức dịch vụ cộng với các chú thích đường dẫn và param. Nó tách biệt logic khỏi ánh xạ loại url / nội dung (nơi cao su chạm đường để nói).
Stijn de Witt

thật ra, người ta chỉ có thể trả lại đối tượng không gói vào Phản hồi.
vừng

191

Có một số trường hợp sử dụng để đặt mã trạng thái HTTP trong dịch vụ web REST và ít nhất một trường hợp không được ghi lại đầy đủ trong các câu trả lời hiện có (nghĩa là khi bạn đang sử dụng tuần tự hóa JSON / XML tự động bằng JAXB và bạn muốn trả về đối tượng được tuần tự hóa, nhưng cũng là một mã trạng thái khác với 200 mặc định).

Vì vậy, hãy để tôi thử và liệt kê các trường hợp sử dụng khác nhau và các giải pháp cho từng trường hợp:

1. Mã lỗi (500, 404, ...)

Trường hợp sử dụng phổ biến nhất khi bạn muốn trả về mã trạng thái khác với 200 OKkhi xảy ra lỗi.

Ví dụ:

  • một thực thể được yêu cầu nhưng nó không tồn tại (404)
  • yêu cầu không đúng về mặt ngữ nghĩa (400)
  • người dùng không được ủy quyền (401)
  • có vấn đề với kết nối cơ sở dữ liệu (500)
  • Vân vân..

a) Ném một ngoại lệ

Trong trường hợp đó, tôi nghĩ rằng cách sạch nhất để xử lý vấn đề là ném ngoại lệ. Ngoại lệ này sẽ được xử lý bởi một ExceptionMapper, sẽ chuyển ngoại lệ thành phản hồi với mã lỗi thích hợp.

Bạn có thể sử dụng mặc định ExceptionMapperđược cấu hình sẵn với Jersey (và tôi đoán nó giống với các triển khai khác) và ném bất kỳ lớp con hiện có nào javax.ws.rs.WebApplicationException. Đây là các loại ngoại lệ được xác định trước được ánh xạ trước tới các mã lỗi khác nhau, ví dụ:

  • BadRequestException (400)
  • InternalServerErrorException (500)
  • NotFoundException (404)

V.v. Bạn có thể tìm thấy danh sách ở đây: API

Ngoài ra, bạn có thể xác định các ngoại lệ và ExceptionMapperlớp tùy chỉnh của riêng mình và thêm các trình ánh xạ này vào Jersey bằng phương tiện của @Providerchú thích ( nguồn của ví dụ này ):

public class MyApplicationException extends Exception implements Serializable
{
    private static final long serialVersionUID = 1L;
    public MyApplicationException() {
        super();
    }
    public MyApplicationException(String msg)   {
        super(msg);
    }
    public MyApplicationException(String msg, Exception e)  {
        super(msg, e);
    }
}

Các nhà cung cấp :

    @Provider
    public class MyApplicationExceptionHandler implements ExceptionMapper<MyApplicationException> 
    {
        @Override
        public Response toResponse(MyApplicationException exception) 
        {
            return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();  
        }
    }

Lưu ý: bạn cũng có thể viết ExceptionMappers cho các loại ngoại lệ hiện có mà bạn sử dụng.

b) Sử dụng trình xây dựng Phản hồi

Một cách khác để đặt mã trạng thái là sử dụng trình Responsexây dựng để tạo phản hồi với mã dự định.

Trong trường hợp đó, kiểu trả về của phương thức của bạn phải là javax.ws.rs.core.Response. Điều này được mô tả trong nhiều câu trả lời khác như câu trả lời được chấp nhận của anh ấy và trông như thế này:

@GET
@Path("myresource({id}")
public Response retrieveSomething(@PathParam("id") String id) {
    ...
    Entity entity = service.getById(uuid);
    if(entity == null) {
        return Response.status(Response.Status.NOT_FOUND).entity("Resource not found for ID: " + uuid).build();
    }
    ...
}

2. Thành công, nhưng không phải 200

Một trường hợp khác khi bạn muốn đặt trạng thái trả về là khi thao tác thành công, nhưng bạn muốn trả về mã thành công khác 200, cùng với nội dung mà bạn trả về trong phần thân.

Trường hợp sử dụng thường xuyên là khi bạn tạo một thực thể ( POSTyêu cầu) mới và muốn trả về thông tin về thực thể mới này hoặc có thể là chính thực thể đó, cùng với 201 Createdmã trạng thái.

Một cách tiếp cận là sử dụng đối tượng phản hồi giống như được mô tả ở trên và tự đặt cơ thể của yêu cầu. Tuy nhiên, bằng cách này, bạn mất khả năng sử dụng tuần tự hóa tự động sang XML hoặc JSON do JAXB cung cấp.

Đây là phương thức ban đầu trả về một đối tượng thực thể sẽ được tuần tự hóa thành JSON bởi JAXB:

@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public User addUser(User user){
    User newuser = ... do something like DB insert ...
    return newuser;
}

Điều này sẽ trả về một đại diện JSON của người dùng mới được tạo, nhưng trạng thái trả về sẽ là 200, không phải 201.

Bây giờ vấn đề là nếu tôi muốn sử dụng trình Responsexây dựng để đặt mã trả về, tôi phải trả về một Responseđối tượng trong phương thức của mình. Làm thế nào để tôi vẫn trả lại Userđối tượng được nối tiếp?

a) Đặt mã trên phản hồi của servlet

Một cách tiếp cận để giải quyết vấn đề này là lấy một đối tượng yêu cầu servlet và tự đặt mã phản hồi theo cách thủ công, như thể hiện trong câu trả lời của Garett Wilson:

@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public User addUser(User user, @Context final HttpServletResponse response){

    User newUser = ...

    //set HTTP code to "201 Created"
    response.setStatus(HttpServletResponse.SC_CREATED);
    try {
        response.flushBuffer();
    }catch(Exception e){}

    return newUser;
}

Phương thức vẫn trả về một đối tượng thực thể và mã trạng thái sẽ là 201.

Lưu ý rằng để làm cho nó hoạt động, tôi đã phải trả lời. Đây là sự hồi sinh khó chịu của mã API Servlet cấp thấp trong tài nguyên JAX_RS tốt đẹp của chúng tôi và tệ hơn nữa, nó khiến các tiêu đề không thể thay đổi được sau khi chúng được gửi trên dây.

b) Sử dụng đối tượng phản hồi với thực thể

Giải pháp tốt nhất, trong trường hợp đó là sử dụng đối tượng Phản hồi và đặt thực thể được tuần tự hóa trên đối tượng phản hồi này. Sẽ tốt hơn nếu làm cho đối tượng Phản hồi chung chung để chỉ ra loại thực thể tải trọng trong trường hợp đó, nhưng không phải là trường hợp hiện tại.

@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response addUser(User user){

    User newUser = ...

    return Response.created(hateoas.buildLinkUri(newUser, "entity")).entity(restResponse).build();
}

Trong trường hợp đó, chúng tôi sử dụng phương thức đã tạo của lớp Trình tạo phản hồi để đặt mã trạng thái thành 201. Chúng tôi chuyển đối tượng thực thể (người dùng) cho phản hồi thông qua phương thức thực thể ().

Kết quả là mã HTTP là 401 như chúng ta muốn và phần thân của phản hồi là chính xác JSON như chúng ta đã có trước đây khi chúng ta vừa trả về đối tượng Người dùng. Nó cũng thêm một tiêu đề vị trí.

Lớp Phản hồi có một số phương thức xây dựng cho các trạng thái khác nhau (stati?), Như:

Feedback.accepted () Feedback.ok () Feedback.noContent () Feedback.notAcceptable ()

NB: đối tượng ghét là một lớp trợ giúp mà tôi đã phát triển để giúp tạo các URI tài nguyên. Bạn sẽ cần phải đưa ra cơ chế của riêng mình ở đây;)

Đó là về nó.

Tôi hy vọng câu trả lời dài dòng này sẽ giúp được ai đó :)


Tôi tự hỏi nếu có một cách rõ ràng để trả về chính đối tượng dữ liệu thay vì phản hồi. Các flushthực sự bẩn.
AlikElzin-kilaka

1
Chỉ là một tiểu thú cưng của tôi: 401 không có nghĩa là người dùng không được ủy quyền. Điều đó có nghĩa là máy khách không được ủy quyền, vì máy chủ không biết bạn là ai. Nếu người dùng đã đăng nhập / được công nhận khác không được phép thực hiện một hành động nhất định, mã phản hồi chính xác là 403 Bị cấm.
Demonblack

69

Câu trả lời bởi sự nhạy bén của anh ấy sẽ hoạt động, nhưng nó sửa đổi toàn bộ cách tiếp cận để cho phép một nhà cung cấp như Jackson + JAXB tự động chuyển đổi đối tượng trả về của bạn sang một số định dạng đầu ra như JSON. Lấy cảm hứng từ một bài viết CXF của Apache (sử dụng lớp dành riêng cho CXF) Tôi đã tìm thấy một cách để đặt mã phản hồi sẽ hoạt động trong bất kỳ triển khai JAX-RS nào: tiêm bối cảnh httpServletResponse và tự đặt mã phản hồi. Ví dụ, đây là cách đặt mã phản hồi CREATEDkhi thích hợp.

@Path("/foos/{fooId}")
@PUT
@Consumes("application/json")
@Produces("application/json")
public Foo setFoo(@PathParam("fooID") final String fooID, final Foo foo, @Context final HttpServletResponse response)
{
  //TODO store foo in persistent storage
  if(itemDidNotExistBefore) //return 201 only if new object; TODO app-specific logic
  {
    response.setStatus(Response.Status.CREATED.getStatusCode());
  }
  return foo;  //TODO get latest foo from storage if needed
}

Cải thiện: Sau khi tìm thấy một câu trả lời liên quan khác , tôi đã học được rằng người ta có thể đưa vào HttpServletResponsebiến thành thành viên, ngay cả đối với lớp dịch vụ đơn lẻ (ít nhất là trong REST EAS) !! Đây là một cách tiếp cận tốt hơn nhiều so với việc gây ô nhiễm API với các chi tiết triển khai. Nó sẽ trông như thế này:

@Context  //injected response proxy supporting multiple threads
private HttpServletResponse response;

@Path("/foos/{fooId}")
@PUT
@Consumes("application/json")
@Produces("application/json")
public Foo setFoo(@PathParam("fooID") final String fooID, final Foo foo)
{
  //TODO store foo in persistent storage
  if(itemDidNotExistBefore) //return 201 only if new object; TODO app-specific logic
  {
    response.setStatus(Response.Status.CREATED.getStatusCode());
  }
  return foo;  //TODO get latest foo from storage if needed
}

Bạn thực sự có thể kết hợp các cách tiếp cận: chú thích phương thức với @Producesvà không chỉ định loại phương tiện trong trận chung kết Response.okvà bạn sẽ đưa đối tượng trả về của mình chính xác JAXB được xê-ri hóa thành loại phương tiện phù hợp để phù hợp với yêu cầu. (Tôi vừa thử điều này với một phương thức duy nhất có thể trả về XML hoặc JSON: bản thân phương thức đó không cần đề cập đến, ngoại trừ trong @Produceschú thích.)
Royston Shufflebotham

Bạn nói đúng Garret. Ví dụ của tôi là một minh họa về sự nhấn mạnh của việc cung cấp một loại nội dung. Cách tiếp cận của chúng tôi tương tự nhau, nhưng ý tưởng sử dụng a MessageBodyWriterProvidercho phép đàm phán nội dung ngầm, mặc dù có vẻ như ví dụ của bạn thiếu một số mã. Đây là một câu trả lời khác mà tôi đã cung cấp minh họa điều này: stackoverflow.com/questions/5161466/
triệt

8
Tôi không thể ghi đè mã trạng thái response.setStatus(). Cách duy nhất để gửi ví dụ phản hồi 404 Không tìm thấy là đặt mã trạng thái phản hồi response.setStatus(404)sau đó đóng luồng đầu ra response.getOutputStream().close()để JAX-RS không thể đặt lại trạng thái của tôi.
Rob Juurlink

2
Tôi đã có thể sử dụng phương pháp này để đặt mã 201, nhưng phải thêm một khối thử bắt response.flushBuffer()để tránh khung làm việc ghi đè mã phản hồi của tôi. Không sạch lắm.
Pierre Henry

1
@RobJuurlink, nếu bạn muốn trả lại một cách cụ thể 404 Not Found, có thể dễ dàng hơn để sử dụng throw new NotFoundException().
Garret Wilson

34

Nếu bạn muốn giữ cho lớp tài nguyên của bạn sạch các Responseđối tượng, thì tôi khuyên bạn nên sử dụng @NameBindingvà ràng buộc với việc triển khai ContainerResponseFilter.

Đây là phần thịt của chú thích:

package my.webservice.annotations.status;

import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Status {
  int CREATED = 201;
  int value();
}

Đây là thịt của bộ lọc:

package my.webservice.interceptors.status;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;

@Provider
public class StatusFilter implements ContainerResponseFilter {

  @Override
  public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
    if (containerResponseContext.getStatus() == 200) {
      for (Annotation annotation : containerResponseContext.getEntityAnnotations()) {
        if(annotation instanceof Status){
          containerResponseContext.setStatus(((Status) annotation).value());
          break;
        }
      }
    }
  }
}

Và sau đó, việc thực hiện trên tài nguyên của bạn chỉ đơn giản trở thành:

package my.webservice.resources;

import my.webservice.annotations.status.StatusCreated;
import javax.ws.rs.*;

@Path("/my-resource-path")
public class MyResource{
  @POST
  @Status(Status.CREATED)
  public boolean create(){
    return true;
  }
}

Giữ API sạch sẽ, câu trả lời hay. Có thể tham số hóa chú thích của bạn như @Status (code = 205) và có bộ chặn chặn thay thế mã bằng bất cứ thứ gì bạn chỉ định không? Tôi nghĩ rằng về cơ bản sẽ cung cấp cho bạn một chú thích để ghi đè mã bất cứ khi nào bạn cần.
dùng2800708

@ user2800708, tôi đã làm điều này cho mã địa phương của mình, đã cập nhật câu trả lời như bạn đề xuất.
Nthalk

Tốt đẹp, cảm ơn. Với điều này và một vài thủ thuật, về cơ bản giờ đây tôi có thể dọn sạch các API REST trong mã của mình, để nó phù hợp với giao diện Java đơn giản mà không đề cập đến REST trong đó; nó chỉ là một cơ chế RMI khác.
dùng2800708

6
Thay vì lặp cho các chú thích trong StatusFilter, bạn có thể chú thích bộ lọc với @ Status ngoài @ Nhà cung cấp. Sau đó, bộ lọc sẽ chỉ được gọi trên các tài nguyên được chú thích bằng @ Status. Đây là mục đích của @ NameBinding
trevorism

1
Lời kêu gọi tốt @trevorism. Có một hiệu ứng phụ không hay lắm khi chú thích StatusFiltervới @Status: bạn cần cung cấp mặc định cho trường của chú thích valuehoặc khai báo một khi chú thích lớp (ví dụ @Status(200):). Điều này rõ ràng là không lý tưởng.
Phil

6

Trong trường hợp bạn muốn thay đổi mã trạng thái vì một ngoại lệ, với JAX-RS 2.0, bạn có thể triển khai ExceptionMapper như thế này. Điều này xử lý loại ngoại lệ cho toàn bộ ứng dụng.

@Provider
public class UnauthorizedExceptionMapper implements ExceptionMapper<EJBAccessException> {

    @Override
    public Response toResponse(EJBAccessException exception) {
        return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
    }

}

6

Nếu WS-RS của bạn cần phát sinh lỗi, tại sao không sử dụng WebApplicationException?

@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path("{id}")
public MyEntity getFoo(@PathParam("id") long id,  @QueryParam("lang")long idLanguage) {

if (idLanguage== 0){
    // No URL parameter idLanguage was sent
    ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
    builder.entity("Missing idLanguage parameter on request");
    Response response = builder.build();
    throw new WebApplicationException(response);
    }
... //other stuff to return my entity
return myEntity;
}

4
Theo tôi, WebApplicationExceptions không phù hợp với lỗi phía máy khách vì chúng ném dấu vết ngăn xếp lớn. Lỗi máy khách không được ném dấu vết ngăn xếp phía máy chủ và gây ô nhiễm khi đăng nhập với nó.
Rob Juurlink

5

JAX-RS có hỗ trợ mã HTTP tiêu chuẩn / tùy chỉnh. Xem FeedbackBuilder và FeedbackStatus, ví dụ:

http://jackson.codehaus.org/javadoc/jax-rs/1.0/javax/ws/rs/core/Response.ResponseBuilder.html#status%28javax.ws.rs.core.Response.Status%29

Hãy nhớ rằng thông tin JSON liên quan nhiều hơn đến dữ liệu được liên kết với tài nguyên / ứng dụng. Các mã HTTP nói thêm về trạng thái của hoạt động CRUD được yêu cầu. (ít nhất đó là cách nó được cho là trong các hệ thống REST-Ful)


liên kết bị hỏng
Umpa

5

Tôi thấy nó rất hữu ích để xây dựng một thông điệp json với mã lặp đi lặp lại, như thế này:

@POST
@Consumes("application/json")
@Produces("application/json")
public Response authUser(JsonObject authData) {
    String email = authData.getString("email");
    String password = authData.getString("password");
    JSONObject json = new JSONObject();
    if (email.equalsIgnoreCase(user.getEmail()) && password.equalsIgnoreCase(user.getPassword())) {
        json.put("status", "success");
        json.put("code", Response.Status.OK.getStatusCode());
        json.put("message", "User " + authData.getString("email") + " authenticated.");
        return Response.ok(json.toString()).build();
    } else {
        json.put("status", "error");
        json.put("code", Response.Status.NOT_FOUND.getStatusCode());
        json.put("message", "User " + authData.getString("email") + " not found.");
        return Response.status(Response.Status.NOT_FOUND).entity(json.toString()).build();
    }
}

4

Vui lòng xem ví dụ ở đây, nó minh họa rõ nhất vấn đề và cách giải quyết trong phiên bản mới nhất (2.3.1) của Jersey.

https://jersey.java.net/documentation/latest/interesentations.html#d0e3586

Về cơ bản nó liên quan đến việc xác định một Ngoại lệ tùy chỉnh và giữ kiểu trả về làm thực thể. Khi có lỗi, ngoại lệ được đưa ra, nếu không, bạn trả lại POJO.


Tôi muốn thêm rằng ví dụ về sự quan tâm là cái mà họ định nghĩa lớp ngoại lệ của riêng họ và xây dựng một lớp Responsetrong đó. Chỉ cần tìm CustomNotFoundExceptionlớp và có thể sao chép nó vào bài viết của bạn.
JBert

Tôi sử dụng phương pháp này cho các lỗi và tôi thích nó. Nhưng nó không áp dụng cho các mã thành công (khác 200), chẳng hạn như '201 được tạo'.
Pierre Henry

3

Tôi không sử dụng JAX-RS, nhưng tôi đã có một kịch bản tương tự khi tôi sử dụng:

response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());

Nó làm cho tôi bằng Spring MVC nhưng có một cách dễ dàng để tìm hiểu!

1

Ngoài ra, lưu ý rằng theo mặc định Jersey sẽ ghi đè lên phần phản hồi trong trường hợp mã http 400 trở lên.

Để lấy thực thể được chỉ định của bạn làm cơ quan phản hồi, hãy thử thêm init-param sau vào Jersey của bạn trong tệp cấu hình web.xml của bạn:

    <init-param>
        <!-- used to overwrite default 4xx state pages -->
        <param-name>jersey.config.server.response.setStatusOverSendError</param-name>
        <param-value>true</param-value>
    </init-param>

0

Các mã sau đây làm việc cho tôi. Tách thông điệpContext thông qua setter có chú thích và đặt mã trạng thái trong phương thức "thêm" của tôi.

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;

import org.apache.cxf.jaxrs.ext.MessageContext;

public class FlightReservationService {

    MessageContext messageContext;

    private final Map<Long, FlightReservation> flightReservations = new HashMap<>();

    @Context
    public void setMessageContext(MessageContext messageContext) {
        this.messageContext = messageContext;
    }

    @Override
    public Collection<FlightReservation> list() {
        return flightReservations.values();
    }

    @Path("/{id}")
    @Produces("application/json")
    @GET
    public FlightReservation get(Long id) {
        return flightReservations.get(id);
    }

    @Path("/")
    @Consumes("application/json")
    @Produces("application/json")
    @POST
    public void add(FlightReservation booking) {
        messageContext.getHttpServletResponse().setStatus(Response.Status.CREATED.getStatusCode());
        flightReservations.put(booking.getId(), booking);
    }

    @Path("/")
    @Consumes("application/json")
    @PUT
    public void update(FlightReservation booking) {
        flightReservations.remove(booking.getId());
        flightReservations.put(booking.getId(), booking);
    }

    @Path("/{id}")
    @DELETE
    public void remove(Long id) {
        flightReservations.remove(id);
    }
}

0

Mở rộng câu trả lời của Nthalk với Microprofile OpenAPI, bạn có thể căn chỉnh mã trả về với tài liệu của mình bằng cách sử dụng chú thích @APIResponse .

Điều này cho phép gắn thẻ phương thức JAX-RS như

@GET
@APIResponse(responseCode = "204")
public Resource getResource(ResourceRequest request) 

Bạn có thể phân tích chú thích được tiêu chuẩn hóa này bằng ContainerResponseFilter

@Provider
public class StatusFilter implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
        if (responseContext.getStatus() == 200) {
            for (final var annotation : responseContext.getEntityAnnotations()) {
                if (annotation instanceof APIResponse response) {
                    final var rawCode = response.responseCode();
                    final var statusCode = Integer.parseInt(rawCode);

                    responseContext.setStatus(statusCode);
                }
            }
        }
    }

}

Một cảnh báo xảy ra khi bạn đặt nhiều chú thích vào phương thức của bạn như

@APIResponse(responseCode = "201", description = "first use case")
@APIResponse(responseCode = "204", description = "because you can")
public Resource getResource(ResourceRequest request) 

-1

Tôi đang sử dụng jersey 2.0 với các độc giả và người viết thông điệp. Tôi đã có kiểu trả về phương thức của mình như một thực thể cụ thể cũng được sử dụng trong quá trình thực thi của trình soạn thảo nội dung thư và tôi đã trả lại cùng một pojo, SkuListDTO. @GET @Consume ({"application / xml", "application / json"}) @Sản phẩm ({"application / xml", "application / json"}) @Path ("/ skuResync")

public SkuResultListDTO getSkuData()
    ....
return SkuResultListDTO;

tất cả tôi đã thay đổi là điều này, tôi đã để việc thực hiện nhà văn một mình và nó vẫn hoạt động.

public Response getSkuData()
...
return Response.status(Response.Status.FORBIDDEN).entity(dfCoreResultListDTO).build();
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.