33

我一直在谷歌搜索我的屁股试图找出如何做到这一点:我有一个 Jersey REST 服务。调用 REST 服务的请求包含一个 JSON 对象。我的问题是,从 Jersey POST 方法实现中,我怎样才能访问 HTTP 请求正文中的 JSON?

任何提示,技巧,示例代码的指针将不胜感激。

谢谢...

——史蒂夫

4

7 回答 7

16

正如已经建议的那样,将@ConsumesContent-Type 更改为text/plain将起作用,但从 REST API 的角度来看,它似乎并不正确。

想象一下,您的客户必须将 JSON 发布到您的 API,但需要将 Content-Type 标头指定为text/plain. 在我看来它并不干净。简单来说,如果您的 API 接受 JSON,则请求标头应指定Content-Type: application/json.

为了接受 JSON 但将其序列化为String对象而不是 POJO,您可以实现自定义MessageBodyReader。这样做同样容易,而且您不必在 API 规范上妥协。

值得阅读MessageBodyReader的文档,以便您确切了解它的工作原理。我是这样做的:

步骤 1. 实现自定义MessageBodyReader

@Provider
@Consumes("application/json")
public class CustomJsonReader<T> implements MessageBodyReader<T> {
  @Override
  public boolean isReadable(Class<?> type, Type genericType,
      Annotation[] annotations,MediaType mediaType) {
    return true;
  }

  @Override
  public T readFrom(Class<T> type, Type genericType, Annotation[] annotations,
      MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
      InputStream entityStream) throws IOException, WebApplicationException {

    /* Copy the input stream to String. Do this however you like.
     * Here I use Commons IOUtils.
     */
    StringWriter writer = new StringWriter();
    IOUtils.copy(entityStream, writer, "UTF-8");
    String json = writer.toString();

    /* if the input stream is expected to be deserialized into a String,
     * then just cast it
     */
    if (String.class == genericType)
      return type.cast(json);

    /* Otherwise, deserialize the JSON into a POJO type.
     * You can use whatever JSON library you want, here's
     * a simply example using GSON.
     */
    return new Gson().fromJson(json, genericType);
  }
}

上面的基本概念是检查输入流是否期望转换为String(由 指定Type genericType)。如果是这样,那么只需将 JSON 转换为指定的type(将是 a String)。如果预期的类型是某种 POJO,则使用 JSON 库(例如 Jackson 或 GS​​ON)将其反序列化为 POJO。

步骤 2. 绑定您的MessageBodyReader

这取决于您使用的框架。我发现 Guice 和 Jersey 配合得很好。这是我在 Guice 中绑定MessageBodyReader的方法:

在我的JerseyServletModule 中,我像这样绑定读者——

bind(CustomJsonReader.class).in(Scopes.SINGLETON);

以上CustomJsonReader将 JSON 有效负载反序列化为 POJO,如果您只是想要原始 JSON,则String对象。

这样做的好处是它会接受Content-Type: application/json. 换句话说,您的请求处理程序可以设置为使用 JSON,这似乎是正确的:

@POST
@Path("/stuff")
@Consumes("application/json") 
public void doStuff(String json) {
  /* do stuff with the json string */
  return;
}
于 2013-02-07T12:23:40.327 回答
15

Jersey 支持使用 Jettison 类型 JSONObject 和 JSONArray 对解析的 JSONObject 进行低级访问。

<dependency>
    <groupId>org.codehaus.jettison</groupId>
    <artifactId>jettison</artifactId>
    <version>1.3.8</version>
</dependency>

例如:

{
  "A": "a value",
  "B": "another value"
}


@POST
@Path("/")
@Consumes(MediaType.APPLICATION_JSON) 
public void doStuff(JSONObject json) {
  /* extract data values using DOM-like API */
  String a = json.optString("A");
  Strong b = json.optString("B");
  return;
}

有关更多示例,请参阅Jersey 文档

于 2013-04-26T14:40:29.923 回答
12

我不确定您将如何获取 JSON 字符串本身,但您当然可以获取它包含的数据,如下所示:

定义一个带有 JAXB 注释的 Java 类 (C),它与请求中传递的 JSON 对象具有相同的结构。

例如对于 JSON 消息:

{
  "A": "a value",
  "B": "another value"
}

使用类似的东西:

@XmlAccessorType(XmlAccessType.FIELD)
public class C
{
  public String A;
  public String B;
}

然后,您可以在资源类中使用 C 类型的参数定义一个方法。当 Jersey 调用您的方法时,将基于 POSTed JSON 对象创建 JAXB 对象。

@Path("/resource")
public class MyResource
{
  @POST
  public put(C c)
  {
     doSomething(c.A);
     doSomethingElse(c.B);
  }
}
于 2009-11-02T17:48:53.167 回答
7

这使您可以访问原始帖子。

@POST
@Path("/")
@Consumes("text/plain") 
@Produces(MediaType.APPLICATION_JSON)
public String processRequset(String pData) {
    // do some stuff, 
    return someJson;
}
于 2012-06-12T13:20:16.693 回答
0

提交/发布表单/HTTP.POST,并带有一个参数,其中 JSON 作为值。

@QueryParam jsonString

公共desolveJson(jsonString)

于 2009-11-02T20:23:40.453 回答
0

一些答案说必须使用服务功能consumes=text/plain,但我的 Jersey 版本可以使用application/json类型。杰克逊和泽西版本是 jackson-core=2.6.1, jersey-common=2.21.0.

@POST
@Path("/{name}/update/{code}")
@Consumes({ "application/json;charset=UTF-8" })
@Produces({ "application/json;charset=UTF-8" })
public Response doUpdate(@Context HttpServletRequest req, @PathParam("name") String name, 
      @PathParam("code") String code, String reqBody) {
  System.out.println(reqBody);

  StreamingOutput stream = new StreamingOutput() {
    @Override public void write(OutputStream os) throws IOException, WebApplicationException {
      ..my fanzy custom json stream writer..
    }
  };

  CacheControl cc = new CacheControl();
  cc.setNoCache(true);
  return Response.ok().type("application/json;charset=UTF-8")
    .cacheControl(cc).entity(stream).build();
}

application/json客户端使用 json 请求正文提交请求。Servlet 代码可以将字符串解析为 JSON 对象或按原样保存到数据库中。

于 2020-02-05T14:59:16.337 回答
0

简单的解决方案:

如果您只有一个简单的 JSON 对象进入服务器并且您不想创建新的 POJO(java 类),那么只需执行此操作

我发送到服务器的 JSON

{
    "studentId" : 1
}

服务器代码:

    //just to show you the full name of JsonObject class
    import javax.json.JsonObject; 

    @Path("/")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Response deleteStudent(JsonObject json) {
        //Get studentId from body <-------- The relevant part 
        int studentId = json.getInt("studentId");
        
        //Return something if necessery
        return Response.ok().build();
    }
于 2021-11-03T08:59:02.440 回答