表单数据到Java中的REST PUT方法

huangapple go评论63阅读模式
英文:

Form data to rest PUT method in java

问题

我是Java和REST API的初学者。我有一个问题,无法将表单数据从HTML传递到REST的`PUT`方法。当我搜索关于这个问题时,大多数可用的解决方案都是针对`POST`方法的,推荐使用`FormParam`。在我的情况下,会显示以下错误:

> 请求行中收到的方法为源服务器所知,但目标资源不支持该方法。

即使我使用`PathParam`,也会返回相同的错误:

> 请求行中收到的方法为源服务器所知,但目标资源不支持该方法。

还有一些针对Spring Boot的解决方案。但我没有使用那个。

**PUT方法:**

```java
@PUT
@Path("/update")
@Produces(MediaType.TEXT_HTML)
public String updCard(@PathParam("cardNo") String cardNo,  
        @PathParam("reportId") int reportId
        ) throws SQLException { 

    Card c = new Card(cardNo, reportId); 

    System.out.println(cardNo + reportId);
    
    return "";
}

表单:

<form method="PUT" action="rest/card/update">
  <label for="cardNo">Card No: </label> <input type="text" name="cardNo" id="cardNo"><br/>
  <label for="reportId">Report Id:</label> <input type="text" name="reportId" id="reportId"> <br/>
  <button type="submit">Update</button>

那么,在Jersey中如何在PUT方法中获取表单数据呢?


<details>
<summary>英文:</summary>

I am beginner for Java and REST API. I have a problem passing form data from HTML to rest `PUT` method. When I google about this, most solutions available are for `POST` method, that recommended to use `FormParam`. In my case, it shows below error: 

&gt; The method received in the request-line is known by the origin server but not supported by the target resource.

Even I use `PathParam`, same error is returned: 

&gt; The method received in the request-line is known by the origin server but not supported by the target resource.

And some solution for Spring Boot. But I did not use that. 

**PUT method:** 

    @PUT
	@Path(&quot;/update&quot;)
	@Produces(MediaType.TEXT_HTML)
	public String updCard(@PathParam(&quot;cardNo&quot;) String cardNo,  
			@PathParam(&quot;reportId&quot;) int reportId
			) throws SQLException { 

		Card c = new Card(cardNo, reportId); 

		System.out.println(cardNo + reportId);
		
		return &quot;&quot;;
	}

**Form:**


     &lt;form method=&quot;PUT&quot; action=&quot;rest/card/update&quot;&gt;
      &lt;label for = &quot;cardNo&quot;&gt;Card No: &lt;/label&gt; &lt;input type=&quot;text&quot; name = &quot;cardNo&quot; id = &quot;cardNo&quot;&gt;&lt;br/&gt;
      &lt;label for = &quot;reportId&quot;&gt;Report Id:&lt;/label&gt; &lt;input type=&quot;text&quot; name = &quot;reportId&quot; id = &quot;reportId&quot;&gt; &lt;br/&gt;
      &lt;button type=&quot;submit&quot;&gt;Update&lt;/button&gt;  


So, how do I get the form data in `PUT` method in Jersey? 



</details>


# 答案1
**得分**: 1

如许多人在[在HTML表单中使用PUT方法][stack-put]中提到的,HTML标准目前不支持PUT方法。大多数框架将提供一种变通方法。Jersey框架通过其[HttpMethodOverrideFilter][jersey-filter]提供了这样的解决方法。你需要做的是使用POST方法并添加一个 `_method=put` 查询参数,过滤器将把POST请求转换为PUT请求。

你首先需要注册这个过滤器。如果你正在使用`ResourceConfig`,只需执行以下操作:

```java
@ApplicationPath("api")
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig() {
        ...
        register(HttpMethodOverrideFilter.class);
    }
}

如果你在使用web.xml,则需要执行以下操作:

<init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
    <param-value>org.glassfish.jersey.server.filter.HttpMethodOverrideFilter</param-value>
</init-param>

然后在你的HTML中,只需在URL中添加 _method=put 查询参数。以下是我用来测试的示例:

<form method="post" action="/api/form?_method=put">
    <label>
        Name:
        <input type="text" name="name"/>
    </label>
    <label>
        Age:
        <input type="number" name="age"/>
    </label>
    <br/>
    <input type="submit" value="Submit"/>
</form>

在你的资源方法中,你将使用 @PUT@FormParam 来处理参数:

@PUT
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response form(@FormParam("name") String name,
                     @FormParam("age") String age,
                     @Context UriInfo uriInfo) {

    URI redirectUri = UriBuilder
            .fromUri(getBaseUriWithoutApiRoot(uriInfo))
            .path("redirect.html")
            .queryParam("name", name)
            .queryParam("age", age)
            .build();
    return Response.temporaryRedirect(redirectUri).build();
}

private static URI getBaseUriWithoutApiRoot(UriInfo uriInfo) {
    String baseUri = uriInfo.getBaseUri().toASCIIString();
    baseUri = baseUri.endsWith("/")
            ? baseUri.substring(0, baseUri.length() - 1)
            : baseUri;
    return URI.create(baseUri.substring(0, baseUri.lastIndexOf("/")));
}

根据我的测试,这应该可以正常工作。

英文:

As mentioned by many in Using PUT method in HTML form, PUT is not currently supported by the HTML standard. What most frameworks will do is offer a workaround. Jersey has such a workaround with its HttpMethodOverrideFilter. What you must do is use a POST method and add a _method=put query parameter and the filter will switch the POST to a PUT.

You first need to register the filter. If you are using a ResourceConfig just do

@ApplicationPath(&quot;api&quot;)
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig() {
        ...
        register(HttpMethodOverrideFilter.class);
    }
}

If you are using a web.xml, then do

&lt;init-param&gt;
    &lt;param-name&gt;jersey.config.server.provider.classnames&lt;/param-name&gt;
    &lt;param-value&gt;org.glassfish.jersey.server.filter.HttpMethodOverrideFilter&lt;/param-value&gt;
&lt;/init-param&gt;

Then in your HTML, you will just add the _method=put query param to the URL. Below is an example I used to test

&lt;form method=&quot;post&quot; action=&quot;/api/form?_method=put&quot;&gt;
    &lt;label&gt;
        Name:
        &lt;input type=&quot;text&quot; name=&quot;name&quot;/&gt;
    &lt;/label&gt;
    &lt;label&gt;
        Age:
        &lt;input type=&quot;number&quot; name=&quot;age&quot;/&gt;
    &lt;/label&gt;
    &lt;br/&gt;
    &lt;input type=&quot;submit&quot; value=&quot;Submit&quot;/&gt;
&lt;/form&gt;

And in your resource method you will use @PUT and @FormParams for the paramters

@PUT
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response form(@FormParam(&quot;name&quot;) String name,
                     @FormParam(&quot;age&quot;) String age,
                     @Context UriInfo uriInfo) {

    URI redirectUri = UriBuilder
            .fromUri(getBaseUriWithoutApiRoot(uriInfo))
            .path(&quot;redirect.html&quot;)
            .queryParam(&quot;name&quot;, name)
            .queryParam(&quot;age&quot;, age)
            .build();
    return Response.temporaryRedirect(redirectUri).build();
}

private static URI getBaseUriWithoutApiRoot(UriInfo uriInfo) {
    String baseUri = uriInfo.getBaseUri().toASCIIString();
    baseUri = baseUri.endsWith(&quot;/&quot;)
            ? baseUri.substring(0, baseUri.length() - 1)
            : baseUri;
    return URI.create(baseUri.substring(0, baseUri.lastIndexOf(&quot;/&quot;)));
}

It should work from what I tested

huangapple
  • 本文由 发表于 2020年10月8日 21:31:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/64263617.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定