Hir*_*oki 3 java rest jax-rs put http-method
根据这篇文章(http://restcookbook.com/HTTP%20Methods/put-vs-post/),PUT应该作为更新资源的方法.
但是,使用JAX_RS 2.0和Jersey 2.0练习RESTful,我认为它不会更新特定资源.(即我正在使用JAX_RS 2.0和Jersey 2.0学习RESTful)
这是一个这样的资源.
<customer>
<name>Before</name>
<postcode>111</postcode>
</customer>
Run Code Online (Sandbox Code Playgroud)
我想要做的是更新(也许我应该说"替换")这个资源.
ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
WebTarget target = client.target("http://xxx/yyy/zzz/end.cust");
Customer cust = new Customer();
cust.setName("After");
cust.setPostcode(222);
target.path("Before").request().put(Entity.xml(cust));
Run Code Online (Sandbox Code Playgroud)
@Id注释在"Customer"类中设置为"Name",因此路径"Before"应该作为ID工作,第一个资源(名为"Before")应该替换为第二个资源(名为"After") ").
但是,在执行上面的编码之后,"之前"资源仍然存在,并且有一个新的"After"resrouce.似乎PUT方法可以创建一个新资源,而不是更新某些东西.(即有"之前"和"之后"资源,并且没有更新任何内容)
我测试了一个POST方法以创建一个新资源,并按照我的预期创建了一个新资源.
如果你看到我做错了什么或需要做什么,你能提出一些建议吗?
编辑
我将添加服务器端代码.用@PUT注释的方法是这样的.
@PUT
@Path("{id}")
@Consumes({"application/xml", "application/json"})
public void edit(@PathParam("id") String id, Customer entity) {
super.edit(entity);
}
Run Code Online (Sandbox Code Playgroud)
这是在一个名为CustomerFacadeREST.java的类中,在我创建"来自数据库的RESTful服务"后自动创建.
根据NetBeans的文档,super.edit()方法最初是这样的.
public void edit(T entity) {
getEntityManager().merge(entity);
}
Run Code Online (Sandbox Code Playgroud)
在"Customer"类中,@ Id以这种方式设置为"name"值.
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 80)
@Column(name = "Name")
private String name;
// Other fields, such as Postcode...
public Customer() {
}
// Other constructors and methods...
}
Run Code Online (Sandbox Code Playgroud)
"HTTP动词"背后的想法,如PUT,GET,POST,DELETE只是协议语义的问题.只是执行HTTP PUT操作不会做任何神奇的事情.这是开发人员在开发时应该理解的正确语义,因为这些语义是众所周知的(这就是协议存在的原因).如果没有人遵循这些语义,世界将介于大萧条和天启之间.
话虽这么说,这些动词(语义)是一种保证(或者可能是一个更好的词),对于执行请求的客户端,某个动词将具有一些已知的语义.一个主要因素是幂等性的概念.幂等性是这样的想法:无论我提出多少次请求,结果都是相同的(或具有相同的效果).
某些HTTP动词被认为是幂等的,例如PUT,DELETE,GET.无论多少次提出完全相同的请求,一般的想法是结果/效果应该是相同的.另一方面,POST被认为不是幂等的,因为完全相同的POST请求可能产生不同的结果,例如,提交订单,错误地,再次或创建新客户两次.
如果我们想让世界变得更美好,并为拯救世界免于完全崩溃而尽自己的本分,我们应该学习这些语义并遵循它们成为好公民.除了幂等性之外,还有更多关于动词语义的知识,但理解这一点,是一个好的开始.我建议你可以拿一本关于REST的好书来学习一些好的做法.或者,如果你想要成为一个很酷的孩子,花点时间阅读圣经(实际上是菲尔丁论文).
总而言之,作为开发人员,我们的工作是创建遵循这些语义的代码.您的方法创建新资源的原因可能是因为您正在使用代码创建新资源.也许这样的事情似乎更合适:
@PUT
@Path("/customers/{id}")
@Consumes(MediaType.APPLICATION_JSON)
public Response updateCustomer(@PathParam("id") long id,
Customer updateCustomer) {
Customer customer = customerService.getCustomerById(id);
if (customer == null) {
throw new WebApplicationException("Can't find it", 404);
}
customer.setFirstName(updateCustomer.getFirstName());
customer.setLastName(updateCustomer.getLastName());
...
return Response.noContent().build();
}
Run Code Online (Sandbox Code Playgroud)
所以我们只是更新我们数据库中已存在的客户.通常,在更新PUT请求时,应该知道特定的客户资源URI.所以说客户提出请求http://blah.com/api/customers/1234,我们的服务将使用id查找客户1234.如果找不到,我们返回404状态代码,因为资源不存在.如果确实存在,那么我们使用请求中提供的客户数据更新客户.如果您想创建一个新客户,其中URI未知,那么POST将是正确的,您将发送客户表示http://blah.com/api/customers.
还要保留一个仅供参考:在许多情况下这样的情况下,会发生的情况是客户端请求(GET)资源,比如客户,并更新该客户表示,然后将其作为PUT请求发送回更新的客户.在服务器上,它应该使用该信息来更新特定客户的数据,如上面的示例所示.
根据你的编辑.你完全忽略了这应该如何工作的重点.
Customer cust = new Customer();
cust.setName("After");
cust.setPostcode(222);
target.path("Before").request().put(Entity.xml(cust));
Run Code Online (Sandbox Code Playgroud)
这有什么问题,使用new Customer,您将设置标识符"After",这与您正在使用的请求路径中的标识符不同"Before".所以路径变量{id}是"之前".使用此请求URI,您表示要访问ID为"之前"的客户.如我的代码所示,您有责任检查数据库中是否存在ID为"之前"的客户.如果没有,你应该退回一个404 Not Found.name您为new设置的(id)Customer应该是数据库中预期的id.因此,如果您想在数据库"After"中更新id为id的客户.那么你应该把"After"放在路径中,而不是"之前".我们不应该尝试更改标识符.
就像我说的,当我们想要更新资源时,我们通常会获取资源,更新一些字段(但不是标识符),然后将其发回.序列可能看起来像
final String PATH = "http://hello.com/api/customers"
WebTarget target = client.target(PATH);
Customer customer = target.path("1234").request().get(Customer.class);
// where 1234 is the id (or in your case `name` of the customer.
// I would avoid using the name as the DB id, that's why my example uses numbers
customer.setPostalCode(...);
target = client.target(PATH).path(customer.getName()); // getName should be 1234
Response response = target.request().put(Entity.xml(customer));
Run Code Online (Sandbox Code Playgroud)
我们在路径中使用与我们提供的相同的id,因为这是在服务器中识别资源的方式.
| 归档时间: |
|
| 查看次数: |
7357 次 |
| 最近记录: |