RestTemplate PATCH request

匿名 (未验证) 提交于 2019-12-03 01:20:02

问题:

I have the following definition for PersonDTO:

public class PersonDTO {     private String id     private String firstName;     private String lastName;     private String maritalStatus; } 

Here is a sample record :

{     "id": 1,     "firstName": "John",     "lastName": "Doe",     "maritalStatus": "married" } 

Now, John Doe gets divorced. So I need to send a PATCH request to this URL:

http://localhost:8080/people/1 

With the following request body:

{     "maritalStatus": "divorced" } 

I cannot figure out how to do it. Here is what I tried so far:

// Create Person PersonDTO person = new PersonDTO(); person.setMaritalStatus("Divorced");  // Create HttpEntity final HttpEntity requestEntity = new HttpEntity(person);  // Create URL (for eg: localhost:8080/people/1) final URI url = buildUri(id);  ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.PATCH, requestEntity, Void.class); 

Here are the problems with the above:

1) As I am setting only MaritalStatus, the other fields would all be null. So if I print out the request, it will look like this:

{     "id": null,     "firstName": "null",     "lastName": "null",     "maritalStatus": "married" // I only need to update this field. } 

Does that mean that I have to a GET before I do a PATCH?

2) I am getting the following stack trace:

08:48:52.717 ERROR c.n.d.t.s.PersonServiceImpl - Unexpected Exception  :  org.springframework.web.client.ResourceAccessException: I/O error on PATCH request for "http://localhost:8080/people/1":Invalid HTTP method: PATCH; nested exception is java.net.ProtocolException: Invalid HTTP method: PATCH     at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:580) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:545) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:466) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at com.sp.restclientexample..service.PersonServiceImpl.doPatch(PersonServiceImpl.java:75) ~[classes/:na]     at com.sp.restclientexample..service.PatchTitle.itDoPatch(PatchTitle.java:53) [test-classes/:na]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_20]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_20]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_20]     at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_20]     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) [junit-4.12.jar:4.12]     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12]     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) [junit-4.12.jar:4.12]     at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) [junit-4.12.jar:4.12]     at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) [junit-4.12.jar:4.12]     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12]     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12]     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12]     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12]     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12]     at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12]     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) [.cp/:na]     at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) [.cp/:na]     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) [.cp/:na]     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) [.cp/:na]     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) [.cp/:na]     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) [.cp/:na] Caused by: java.net.ProtocolException: Invalid HTTP method: PATCH     at java.net.HttpURLConnection.setRequestMethod(HttpURLConnection.java:440) ~[na:1.8.0_20]     at sun.net.www.protocol.http.HttpURLConnection.setRequestMethod(HttpURLConnection.java:517) ~[na:1.8.0_20]     at org.springframework.http.client.SimpleClientHttpRequestFactory.prepareConnection(SimpleClientHttpRequestFactory.java:209) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.http.client.SimpleClientHttpRequestFactory.createRequest(SimpleClientHttpRequestFactory.java:138) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.java:76) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:565) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     ... 33 common frames omitted 

Appreciate any pointers from folks who have written client applications to consume a Restful webservice using Spring's RestTemplate.

For completeness, let me also state that we use SpringDataRest for our backend restful webservices.

SGB

回答1:

I solved this problem just adding a new HttpRequestFactory to my restTemplate instance. Like this

RestTemplate restTemplate = new RestTemplate();  HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setConnectTimeout(TIMEOUT); requestFactory.setReadTimeout(TIMEOUT);  restTemplate.setRequestFactory(requestFactory); 

PS: You will need add httpClient component in your project

org.apache.httpcomponentshttpclient4.4.1


回答2:

For cases where RestTemplate is built from a RestTemplateBuilder, constructor for the custom RestClient can be written as,

public PersonRestClient(RestTemplateBuilder restTemplateBuilder) {   this.restTemplate = restTemplateBuilder.requestFactory(new HttpComponentsClientHttpRequestFactory()).build(); } 

Also, the org.apache.httpcomponents.httpclient dependency needs to added to pom.



回答3:

This works for me:

Just used HttpMethod.POST for PATCH request and added "?_method=patch" to url as query param:

For simple RestTemplate call:

RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(handler); String response = restTemplate.postForObject(requestUrl+"?_method=patch",                      requestEntity, String.class); 

For Async Call:

if(method.equalsIgnoreCase("PATCH")){                 requestUrl = requestUrl+"?_method=patch";                 ListenableFuture> responseFuture =                         asyncRestTemplate.exchange(requestUrl, HttpMethod.POST, requestEntity, String.class); responseFuture.addCallback(callBack); } 

This is the call back:

ListenableFutureCallback> callBack = new ListenableFutureCallback>() {        @Override       public void onSuccess(ResponseEntity responseEntity){       // TODO Auto-generated method stub       }         @Override        public void onFailure(Throwable error) {        // TODO Auto-generated method stub        }     }; 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!