在 Jersey 服务中使用 JSON 对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1662490/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Consuming JSON object in Jersey service
提问by Steve
I've been Googling my butt off trying to find out how to do this: I have a Jersey REST service. The request that invokes the REST service contains a JSON object. My question is, from the Jersey POST method implementation, how can I get access to the JSON that is in the body of the HTTP request?
我一直在谷歌上搜索我的屁股试图找出如何做到这一点:我有一个 Jersey REST 服务。调用 REST 服务的请求包含一个 JSON 对象。我的问题是,从 Jersey POST 方法实现中,我如何才能访问 HTTP 请求正文中的 JSON?
Any tips, tricks, pointers to sample code would be greatly appreciated.
任何提示、技巧、示例代码的指针将不胜感激。
Thanks...
谢谢...
--Steve
——史蒂夫
采纳答案by Andy
I'm not sure how you would get at the JSON string itself, but you can certainly get at the data it contains as follows:
我不确定您将如何获取 JSON 字符串本身,但您当然可以获取它包含的数据,如下所示:
Define a JAXB annotated Java class (C) that has the same structure as the JSON object that is being passed on the request.
定义一个 JAXB 带注释的 Java 类 (C),该类与请求中传递的 JSON 对象具有相同的结构。
e.g. for a JSON message:
例如对于 JSON 消息:
{
"A": "a value",
"B": "another value"
}
Use something like:
使用类似的东西:
@XmlAccessorType(XmlAccessType.FIELD)
public class C
{
public String A;
public String B;
}
Then, you can define a method in your resource class with a parameter of type C. When Jersey invokes your method, the JAXB object will be created based on the POSTed JSON object.
然后,您可以在您的资源类中定义一个带有 C 类型参数的方法。当 Jersey 调用您的方法时,将根据 POSTed JSON 对象创建 JAXB 对象。
@Path("/resource")
public class MyResource
{
@POST
public put(C c)
{
doSomething(c.A);
doSomethingElse(c.B);
}
}
回答by pestrella
As already suggested, changing the @ConsumesContent-Type to text/plainwill work, but it doesn't seem right from an REST API point of view.
正如已经建议的那样,将@ConsumesContent-Type更改为text/plain将起作用,但从 REST API 的角度来看似乎并不正确。
Imagine your customer having to POST JSON to your API but needing to specify the Content-Type header as text/plain. It's not clean in my opinion. In simple terms, if your API accepts JSON then the request header should specify Content-Type: application/json.
想象一下,您的客户必须将 JSON POST 到您的 API,但需要将 Content-Type 标头指定为text/plain. 在我看来它并不干净。简单来说,如果您的 API 接受 JSON,则请求标头应指定Content-Type: application/json.
In order to accept JSON but serialize it into a Stringobject rather than a POJO you can implement a custom MessageBodyReader. Doing it this way is just as easy, and you won't have to compromise on your API spec.
为了接受 JSON 但将其序列化为String对象而不是 POJO,您可以实现自定义MessageBodyReader。这样做同样简单,而且您不必在 API 规范上妥协。
It's worth reading the docs for MessageBodyReaderso you know exactly how it works. This is how I did it:
值得阅读MessageBodyReader的文档,以便您确切地知道它是如何工作的。我是这样做的:
Step 1. Implement a custom 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);
}
}
The basic concept above is to check if the input stream is expected to be converted to a String(specified by Type genericType). If so, then simply cast the JSON into the specified type(which will be a String). If the expected type is some sort of POJO, then use a JSON library (e.g. Hymanson or GSON) to deserialize it to a POJO.
上面的基本概念是检查输入流是否需要转换为 a String(由 指定Type genericType)。如果是这样,那么只需将 JSON 转换为指定的type(将是 a String)。如果预期类型是某种 POJO,则使用 JSON 库(例如 Hymanson 或 GSON)将其反序列化为 POJO。
Step 2. Bind your MessageBodyReader
第 2 步。绑定您的MessageBodyReader
This depends on what framework you're using. I find that Guice and Jersey work well together. Here's how I bind my MessageBodyReaderin Guice:
这取决于您使用的框架。我发现 Guice 和 Jersey 配合得很好。这是我在 Guice 中绑定MessageBodyReader的方法:
In my JerseyServletModuleI bind the reader like so --
在我的JerseyServletModule 中,我像这样绑定读者——
bind(CustomJsonReader.class).in(Scopes.SINGLETON);
The above CustomJsonReaderwill deserialize JSON payloads into POJOs as well as, if you simply want the raw JSON, Stringobjects.
以上CustomJsonReader将把 JSON 有效负载反序列化为 POJO,如果您只想要原始 JSON,String对象。
The benefit of doing it this way is that it will accept Content-Type: application/json. In other words, your request handler can be set to consume JSON, which seems proper:
这样做的好处是它会接受Content-Type: application/json. 换句话说,您的请求处理程序可以设置为使用 JSON,这似乎是正确的:
@POST
@Path("/stuff")
@Consumes("application/json")
public void doStuff(String json) {
/* do stuff with the json string */
return;
}
回答by Peter Centgraf
Jersey supports low-level access to the parsed JSONObject using the Jettison types JSONObject and JSONArray.
Jersey 支持使用 Jettison 类型 JSONObject 和 JSONArray 对解析的 JSONObject 进行低级访问。
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.3.8</version>
</dependency>
For example:
例如:
{
"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;
}
See the Jersey documentationfor more examples.
有关更多示例,请参阅Jersey 文档。
回答by Will
This gives you access to the raw post.
这使您可以访问原始帖子。
@POST
@Path("/")
@Consumes("text/plain")
@Produces(MediaType.APPLICATION_JSON)
public String processRequset(String pData) {
// do some stuff,
return someJson;
}
回答by Will
Submit/POST the form/HTTP.POST with a parameter with the JSON as the value.
使用以 JSON 作为值的参数提交/POST 表单/HTTP.POST。
@QueryParam jsonString
@QueryParam jsonString
public desolveJson(jsonString)
公共 desolveJson(jsonString)
回答by Whome
Some of the answers say a service function must use consumes=text/plainbut my Jersey version is fine with application/jsontype. Hymanson and Jersey version is
Hymanson-core=2.6.1, jersey-common=2.21.0.
一些答案说必须使用服务功能,consumes=text/plain但我的 Jersey 版本可以使用application/json类型。Hyman逊和泽西岛版本是
Hymanson-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();
}
Client submits application/jsonrequest with a json request body. Servlet code may parse string to JSON object or save as-is to a database.
客户端application/json使用 json 请求正文提交请求。Servlet 代码可以将字符串解析为 JSON 对象或按原样保存到数据库。

