我正在编写一个REST web应用程序(NetBeans 6.9, JAX-RS, TopLink Essentials),并试图返回JSON和HTTP状态代码。我已经准备好了代码,并在从客户端调用HTTP GET方法时返回JSON。从本质上讲:

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

    // some code to return JSON ...

    return myJson;
}

但是我还想返回一个HTTP状态码(500、200、204等)以及JSON数据。

我尝试使用HttpServletResponse:

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

但这让浏览器认为这是一个“真正的”500,所以输出的网页是一个普通的HTTP 500错误页面。

我想返回一个HTTP状态代码,以便我的客户端JavaScript可以处理一些依赖于它的逻辑(例如,在HTML页面上显示错误代码和消息)。这是可能的还是HTTP状态码不应该用于这样的事情?


当前回答

下面的代码适用于我。通过带注释的setter注入messageContext,并在“add”方法中设置状态代码。

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);
    }
}

其他回答

这里有一个例子:

@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();
}

看一下Response类。

请注意,您应该始终指定一个内容类型,特别是当您传递多个内容类型时,但如果每个消息都将表示为JSON,则可以使用@Produces("application/ JSON ")对方法进行注释。

请看这里的例子,它最好地说明了这个问题,以及在Jersey的最新(2.3.1)版本中是如何解决的。

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

它基本上包括定义一个自定义Exception并将返回类型保留为实体。当出现错误时,抛出异常,否则,返回POJO。

下面的代码适用于我。通过带注释的setter注入messageContext,并在“add”方法中设置状态代码。

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);
    }
}

我使用jersey 2.0的消息体读取器和写入器。我有我的方法返回类型作为一个特定的实体,这也用于实现的消息体作者和我返回相同的pojo,一个SkuListDTO。 @ get @Consumes({“application / xml”、“application / json "}) 与@({“application / xml”、“application / json "}) @ path (" / skuResync”)

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

我所改变的是这个,我离开作家实现单独和它仍然工作。

public Response getSkuData()
...
return Response.status(Response.Status.FORBIDDEN).entity(dfCoreResultListDTO).build();

The answer by hisdrewness will work, but it modifies the whole approach to letting a provider such as Jackson+JAXB automatically convert your returned object to some output format such as JSON. Inspired by an Apache CXF post (which uses a CXF-specific class) I've found one way to set the response code that should work in any JAX-RS implementation: inject an HttpServletResponse context and manually set the response code. For example, here is how to set the response code to CREATED when appropriate.

@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
}

改进:在找到另一个相关的答案后,我了解到可以将HttpServletResponse作为成员变量注入,甚至对于单例服务类(至少在RESTEasy中)!!这是一种比用实现细节污染API更好的方法。它看起来是这样的:

@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
}