我一直在谷歌搜索我的屁股试图找到如何做到这一点:我有一个泽西REST服务。调用REST服务的请求包含JSON对象。我的问题是,从Jersey POST方法实现,我如何才能访问HTTP请求正文中的JSON?
任何提示,技巧,示例代码的指示都将非常感激。
...谢谢
- 史蒂夫
答案 0 :(得分:15)
正如已经建议的那样,将@Consumes
Content-Type更改为text/plain
将会起作用,但从REST API的角度来看似乎并不正确。
想象一下,您的客户必须将POST 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
(将是String
)。如果期望的类型是某种POJO,那么使用JSON库(例如Jackson或GSON)将其反序列化为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;
}
答案 1 :(得分:12)
我不确定你如何获得JSON字符串本身,但你当然可以得到它包含的数据如下:
定义一个JAXB带注释的Java类(C),它具有与在请求中传递的JSON对象相同的结构。
e.g。对于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);
}
}
答案 2 :(得分:12)
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 documentation。
答案 3 :(得分:6)
这使您可以访问原始帖子。
@POST
@Path("/")
@Consumes("text/plain")
@Produces(MediaType.APPLICATION_JSON)
public String processRequset(String pData) {
// do some stuff,
return someJson;
}
答案 4 :(得分:0)
使用带有JSON作为值的参数提交/ POST表单/ HTTP.POST。
@QueryParam jsonString
public desolveJson(jsonString)
答案 5 :(得分: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();
}
客户端使用JSON请求正文提交application/json
请求。 Servlet代码可以将字符串解析为JSON对象,也可以原样保存到数据库中。