我被分配了一项任务,我真的不知道该如何开始解决它,因此我们将不胜感激。考虑以下示例:
@Path("/v1/{server}:{port}/instance")
public class WSInstance {
private static final Log log = LogFactory.getLog(WSInstance.class);
private final String PLANNING_PROPNAME = "**PLNG_NAME**";
private final String PLANNING_PROPVAL = "**CALENDAR_NAME**";
@GET
@Path("/{instanceName}")
@Produces("text/plain")
public String getInstanceStatus(@Context HttpHeaders headers,
@PathParam("server")String server,
@PathParam("port")int port,
@PathParam("instanceName") String instName,
@DefaultValue("") @QueryParam("date") String date,
@DefaultValue("") @QueryParam("instnum") String numexec)
{
return getInstanceStatus(Utils.extractUserInfo(headers), server, port, instName, numexec, date);
}
调用上述方法的示例如下所示:
/v1/serverName:portNumber/instance/toto?date=21090207&instnum=0000
任务要求的是用json替换该URL中的所有变量(serverName
,portNumber
,toto
,date
和instnum
)参数。这是为了简化REST URL。
任何想法从哪里开始?
** 编辑:感谢大家的回答,您当然对我有很大帮助。到目前为止,这是我所做的:
我决定采用“更简单”的类和方法来熟悉该过程。所以我拿了这个:
@Path("/v2/{server}:{port}/admin/")
public class WSAdmin {
private static final Log log = LogFactory.getLog(WSAdmin.class);
@PUT
@Path("/device")
@Produces("text/plain")
@Consumes("application/json")
public String putDevice(String jsonObject, @Context HttpHeaders headers,
@PathParam("server")String server,
@PathParam("port")int port)
{
ObjectMapper mapper = new ObjectMapper();
try
{
return updateDevice(mapper.readTree(jsonObject), Utils.extractUserInfo(headers), server, port);
}
catch (JsonProcessingException e)
{
return e.getMessage();
}
catch (IOException e)
{
return e.getMessage();
}
}
我这样更改它:
@Path("/v2/admin/")
public class WSAdmin {
private static final Log log = LogFactory.getLog(WSAdmin.class);
@POST
@Path("/device")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response putDevice(Admin admin)
{
String output = admin.toString();
return Response.status(200).entity(output).build();
}
然后我创建了相应的POJO:
@XmlRootElement
public class Admin {
private String server;
private int port;
private Date date;
private String instnum;
// Constructors + getters + setters
@Override
public String toString() {
return new StringBuffer("Server: ").append(this.server)
.append("Port: ").append(this.port).append("Date: ")
.append(this.date).append("InstNum: ")
.append(this.instnum).toString();
}
}
然后,我编辑了 web.xml 文件以能够封送和取消封送Java Objets:
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
但是由于某些原因,我从邮递员拨打电话时遇到以下错误:
GRAVE [http-nio-8080-exec-5] com.sun.jersey.spi.container.ContainerRequest.getEntity A message body reader for Java class com.ws.v3.models.Admin, and Java type class com.ws.v3.models.Admin, and MIME media type application/json was not found.
The registered message body readers compatible with the MIME media type are:
application/json ->
com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$App
com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$App
com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$App
*/* ->
com.sun.jersey.core.impl.provider.entity.FormProvider
com.sun.jersey.core.impl.provider.entity.StringProvider
com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
com.sun.jersey.core.impl.provider.entity.FileProvider
com.sun.jersey.core.impl.provider.entity.InputStreamProvider
com.sun.jersey.core.impl.provider.entity.DataSourceProvider
com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General
com.sun.jersey.core.impl.provider.entity.ReaderProvider
com.sun.jersey.core.impl.provider.entity.DocumentProvider
com.sun.jersey.core.impl.provider.entity.SourceProvider$StreamSourceReader
com.sun.jersey.core.impl.provider.entity.SourceProvider$SAXSourceReader
com.sun.jersey.core.impl.provider.entity.SourceProvider$DOMSourceReader
com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$General
com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General
com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General
com.sun.jersey.core.impl.provider.entity.XMLRootObjectProvider$General
com.sun.jersey.core.impl.provider.entity.EntityHolderReader
com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$General
com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$General
有类似错误的人通过在pom.xml中添加gerson
或jersey-json
使其消失。我添加了它们,但问题没有解决。
有什么主意吗?
答案 0 :(得分:0)
可能您必须将方法类型更改为POST,然后在请求的正文中将数据作为json传递。
GET请求
GET /v1/yourServerName:8080/instance/toto?date=21090207&instnum=0000
可以成为以下POST请求
POST /v1/instance
{
"serverName":"yourServerName",
"portNumber":8080,
"date":21090207,
"instnum":"0000"
}
请注意,instnum
不是数字字段,因为您传递了不能表示为数字值的字符串0000。相反,portNumber
和date
可以是数字值。
答案 1 :(得分:0)
考虑使用Jackson。 Jackson映射JSON <->对象。在此处了解如何在Jersey(REST)中使用它: https://www.mkyong.com/webservices/jax-rs/json-example-with-jersey-jackson/
答案 2 :(得分:0)
每specification个GET
请求的有效载荷是未定义的。因此,您应该避免发送带有GET
请求的正文。正如Davide所建议的那样,您应该在这里切换到POST
,因为这里接收到的有效负载的语义是由您(服务器/ API维护者)定义的。
但是,用rest标记了您的帖子后,您可能应该考虑复制20多年来在Web中使用的概念,并将其转换为您的API设计。首先,REST体系结构不关心URI的结构。 URI本身只是指向资源的指针,客户端不需要解释它或修改它。首先,服务器应提供客户做出独特选择所需的所有信息。由于客户端不应该解析和解释URI,因此如何确定客户端是否使用URI?
那么,我们人类如何与网页中的URI交互?通常,它们用人类可读的文本注释,该文本总结了该链接的内容(与上述规范相同)。这种简短但有意义的名称通常称为链接关系名称,应“附加”到每个URI。如果服务器需要更改其URI结构,则读取此类链接关系名称并仅调用随附URI的客户端将能够继续其任务。这是将客户端与服务器分离的重要一步。此类链接关系名称应为standardized,但也可以在common knowlege中指定或在媒体类型本身中指定。
许多所谓的“ REST API”的常见错误是仅支持application/xml
和/或application/json
。在REST架构中,那些媒体类型非常差,因为它们仅定义要使用的语法,而没有定义各个元素的语义。因此,对于客户而言,很难确定此类文档的意图,并且很难陷入typed resource陷阱中并假定某个资源具有某种类型。如果这种(非标准化的)表示形式发生变化,则客户很可能会中断以进一步与该服务/ API进行互操作。
媒体类型或多或少是某种接收到的有效负载的标准化处理规则,应有助于使接收者了解内容的含义以及它可能会做什么。 HTML可能是一种众所周知的媒体类型,它定义了某些元素何时可行以及每个元素具有的约束。它还定义了如何渲染某些元素以及如何与旧版本向后兼容。当支持链接和链接关系时,它是事实上的标准。尽管HAL,Collection+JSON,...在支持链接和关系名称方面朝着正确的方向迈出了一步,但它们提供的语义与HTML的语义相去甚远,尽管它们应该比HTML更可取。纯JSON,因为它们不仅指定语法,而且还指定某些元素(例如_links
)的语义,即有助于客户端区分链接与内容。
就内容类型协商而言,媒体类型尤其重要,在该类型中,客户端请求服务器返回客户端可以理解的表示格式。如果服务器不能产生这样的表示,它将向客户端通知一个足够有表现力的错误代码(406)。如果服务器无法处理客户端提供的媒体类型(在POST,PUT,PATCH,...操作上),则服务器还将通知客户端它不理解这种格式(415)。
关于设计REST API的一般建议是从Web服务器的角度考虑API,并像这样设计与之的整个交互。即如果客户端必须执行证书输入,则不应仅将带有某些随机字段(在某些外部文档中指定)的playin JSON文档发送到服务器,而是服务器应教会客户端如何发送这样的请求作为开始。类似于Web表单,人们应该在Web表单中输入文本和内容,REST API应该返回一种表示公式的媒体类型,该公式可以告诉客户端服务器期望的字段,使用的操作以及将有效负载发送到的目标。
关于实际问题,我不确定您的员工为什么如此热衷于从URI中删除参数。如我在发送有效载荷的第一段中所述,您需要切换到POST
,因此,除了自动执行safe
操作的保证的idempotent
和GET
功能之外,默认情况下不可缓存。
您可以做的就是允许用户或您的同事预先配置某些查询,并为这些预先配置的URI创建简短的URL。在这里,您应该为客户端提供一种类似于表单的媒体类型,在该媒体类型中,客户端可以选择要选择的选项并输入其他必要的数据。收到这样的请求后,您将存储这样的预配置,并在响应的Location标头中返回该预配置的简短URL。您还应该在常规响应中添加预配置的链接,以便客户端在持久化后未立即存储时就能够调用它。这样,您仍然具有GET
操作的优势,同时可以灵活地动态添加新查询或自定义现有查询。如前所述,客户端将无法大量使用纯application/json
表示形式的此类链接。如果客户端支持application/hal+json
,则它可能至少知道什么是链接关系和链接,因此能够通过其附带的链接关系名称来查找和调用URI。基本上,您可以根据需要自由地稍后更改URI结构,而不会影响客户端。