让我们看看发送请求时会发生什么。
情况一:没有延期
您的方法如下所示:
@GET @Path(IMAGE_ID_PATH_PARAM)
@Produces("image/*")
public Response getImage(@PathParam("imageId") String imageId,
@PathParam("extension") String extension, @QueryParam("mods") String mods) {
...
}
@PUT @Path(IMAGE_ID_PATH_PARAM)
@Consumes("image/*")
public Response putImage(@PathParam("imageId") String imageId, File image) {
...
}
当您发送以下请求时:
PUT http://localhost:9090/images/abcde
首先,Jersey 查找具有相关 URI 的资源:
http://localhost:9090/images/abcde
找到资源后,它会检查可以使用哪些方法来访问它。在这种情况下,您有一个资源,其路径由IMAGE_ID_PATH_PARAM
. 这个资源可以被一个GET
或多个PUT
请求访问。就像您在注释中指定的一样。
情况2:扩展添加到getImage
你的方法现在看起来像这样:
@GET @Path(IMAGE_ID_PATH_PARAM + EXTENSION_PATH_PARAM)
@Produces("image/*")
public Response getImage(@PathParam("imageId") String imageId,
@PathParam("extension") String extension, @QueryParam("mods") String mods) {
...
}
@PUT @Path(IMAGE_ID_PATH_PARAM)
@Consumes("image/*")
public Response putImage(@PathParam("imageId") String imageId, File image) {
...
}
同样,您发送相同的请求:
PUT http://localhost:9090/images/abcde
再一次,Jersey 找到了与 URL 匹配的第一个资源。资源由您的getImage
方法表示,就像第一次一样。这一次,@GET
注释与您的请求不匹配。和以前一样,Jersey 会尝试为资源找到另一种可用的方法,以匹配您的请求。
但是,这一次没有找到这样的方法,所以它返回 405。
发生这种情况的原因是方法getImage
和putImage
现在代表不同的资源。如果你仔细看,路径可以这样读取(为了清楚起见,我将省略正则表达式):
@Path({imageId}{extension})
为了getImage
和
@Path({imageId})
为了putImage
虽然考虑到正则表达式,这两条路径可以成为同一事物,但 Jersey 仍将它们视为单独资源的标识符。
如果您查看由 Jersey 生成的 WADL(如果您不熟悉标准,请随意查看此处http://localhost:9090/application.wadl
)文件(它应该在 中可用),您会注意到这正是正在发生的事情。
<application xmlns="http://research.sun.com/wadl/2006/10">
<resources base="http://localhost:9090/">
<resource path="images">
<resource path="{imageId : [A-Za-z0-9_\-]+}">
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="imageId" style="template" type="xs:string"/>
<method id="putImage" name="PUT">
<request>
<representation mediaType="image/*"/>
</request>
<response>
<representation mediaType="*/*"/>
</response>
</method>
</resource>
<resource path="{imageId : [A-Za-z0-9_\-]+}{extension : (\.[A-Za-z]+)?}">
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="extension" style="template" type="xs:string"/>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="imageId" style="template" type="xs:string"/>
<method id="getImage" name="GET">
<request>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="mods" style="query" type="xs:string"/>
</request>
<response>
<representation mediaType="image/*"/>
</response>
</method>
</resource>
</resource>
</resources>
</application>
请注意如何images
有两个独立的子资源,每个子资源都有一个方法。
解决方案
将EXTENSION_PATH_PARAM
段添加到putImage
的@Path
注解会导致这两个方法再次映射到单个资源,因此问题消失了。由于正则表达式使这部分是可选的,因此您可以随意省略它并假装它不存在。
在生成的 WADL 中可以清楚地看到差异。
<application xmlns="http://research.sun.com/wadl/2006/10">
<resources base="http://localhost:9090/">
<resource path="images">
<resource path="{imageId : [A-Za-z0-9_\-]+}{extension : (\.[A-Za-z]+)?}">
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="extension" style="template" type="xs:string"/>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="imageId" style="template" type="xs:string"/>
<method id="putImage" name="PUT">
<request>
<representation mediaType="image/*"/>
</request>
<response>
<representation mediaType="*/*"/>
</response>
</method>
<method id="getImage" name="GET">
<request>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="mods" style="query" type="xs:string"/>
</request>
<response>
<representation mediaType="image/*"/>
</response>
</method>
</resource>
</resource>
</resources>
</application>
在这种情况下,images
只有一个子资源,而子资源又具有两种可用的方法。
就个人而言,我发现 WADL 的自动生成是 Jersey 的一个很棒的功能。这是一种查看资源方法发生情况的好方法,无需花费太多时间使用 curl 或其他 REST 客户端。