Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Json RestTemplate修补程序请求_Json_Spring_Resttemplate - Fatal编程技术网

Json RestTemplate修补程序请求

Json RestTemplate修补程序请求,json,spring,resttemplate,Json,Spring,Resttemplate,我对PersonDTO有以下定义: public class PersonDTO { private String id private String firstName; private String lastName; private String maritalStatus; } 以下是一个示例记录: { "id": 1, "firstName": "John", "lastName": "Doe", "maritalSta

我对PersonDTO有以下定义:

public class PersonDTO
{
    private String id
    private String firstName;
    private String lastName;
    private String maritalStatus;
}
以下是一个示例记录:

{
    "id": 1,
    "firstName": "John",
    "lastName": "Doe",
    "maritalStatus": "married"
}
现在,约翰·多伊离婚了。因此,我需要向此URL发送修补程序请求:

http://localhost:8080/people/1
与以下请求机构:

{
    "maritalStatus": "divorced"
}
我想不出怎么做。以下是我迄今为止所做的尝试:

// Create Person
PersonDTO person = new PersonDTO();
person.setMaritalStatus("Divorced");

// Create HttpEntity
final HttpEntity<ObjectNode> requestEntity = new HttpEntity<>(person);

// Create URL (for eg: localhost:8080/people/1)
final URI url = buildUri(id);

ResponseEntity<Void> responseEntity = restTemplate.exchange(url, HttpMethod.PATCH, requestEntity, Void.class);
这是否意味着我在做补丁之前必须先做一个补丁

2) 我得到以下堆栈跟踪:

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
感谢那些编写了客户端应用程序的人提供的使用Spring的RestTemplate使用Restful Web服务的任何建议

为了完整性,我还要声明,我们将SpringDataRest用于后端REST式Web服务


SGB

我只需在restTemplate实例中添加一个新的HttpRequestFactory,就解决了这个问题。像这样

RestTemplate restTemplate = new RestTemplate();

HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setConnectTimeout(TIMEOUT);
requestFactory.setReadTimeout(TIMEOUT);

restTemplate.setRequestFactory(requestFactory);
对于TestRestTemplate,添加

@Autowired
private TestRestTemplate restTemplate;

@Before
public void setup() {
    restTemplate.getRestTemplate().setRequestFactory(new HttpComponentsClientHttpRequestFactory());
}
PS:您需要在项目中添加httpClient组件

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.4.1</version>
</dependency>

org.apache.httpcomponents
httpclient
4.4.1

对于从
RestTemplateBuilder
构建
RestTemplate
的情况,自定义RestClient的构造函数可以编写为

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

此外,还需要将
org.apache.httpcomponents.httpclient
依赖项添加到pom中

如果您的spring版本比3.1.0旧,那么在HttpMethods中就没有补丁方法。您仍然可以从apache使用HttpClient。下面是我如何做到这一点的一个简短示例:

    try {

        //This is just to avoid ssl hostname verification and to trust all, you can use simple Http client also
        CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();

        HttpPatch request = new HttpPatch(REST_SERVICE_URL);
        StringEntity params = new StringEntity(JSON.toJSONString(payload), ContentType.APPLICATION_JSON);
        request.setEntity(params);
        request.addHeader(org.apache.http.HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        request.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
        //You can use other authorization method, like user credentials
        request.addHeader(HttpHeaders.AUTHORIZATION, OAuth2AccessToken.BEARER_TYPE + " " + accessToken);
        HttpResponse response =     httpClient.execute(request);            

        String statusCode = response.getStatusLine().getStatusCode();

    } catch (Exception ex) {
        // handle exception here
    }
对于RestTemplate,与此等效的是:

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    headers.add("Authorization", OAuth2AccessToken.BEARER_TYPE + " " + accessToken);
    final HttpEntity<String> entity = new HttpEntity<String>(JSON.toJSONString(payload), headers);
    RestTemplate restTemplate = new RestTemplate();
    try {
        ResponseEntity<String> response = restTemplate.exchange(REST_SERVICE_URL, HttpMethod.PATCH, entity, String.class);
        String statusCode =  response.getStatusCode();
    } catch (HttpClientErrorException e) {
        // handle exception here
    }
HttpHeaders=newhttpheaders();
headers.setContentType(MediaType.APPLICATION_JSON);
添加(“授权”,OAuth2AccessToken.BEARER_TYPE+“”+accessToken);
最终HttpEntity实体=新的HttpEntity(JSON.toJSONString(payload),头文件);
RestTemplate RestTemplate=新RestTemplate();
试一试{
ResponseEntity response=restemplate.exchange(REST\u SERVICE\u URL,HttpMethod.PATCH,entity,String.class);
字符串statusCode=response.getStatusCode();
}捕获(HttpClientErrorE异常){
//在这里处理异常
}

另外,确保有效负载只包含需要更改的值,并确保将请求发送到正确的URL。(在某些情况下,这可能是以/api/guest/{id}结尾的内容)

我创建了一个通用方法,用于在涉及链接资源时执行此操作:

public void patch(M theEntity, Integer entityId, String linkName, URI linkUri) {
    ObjectMapper objectMapper = getObjectMapperWithHalModule();
    ObjectNode linkedNode = (ObjectNode) objectMapper.valueToTree(theEntity);
    linkedNode.put(linkName, linkUri.getPath());

    HttpEntity<ObjectNode> requestEntity = new HttpEntity<>(linkedNode);

    restTemplate.exchange(uri + "/" + entityId, HttpMethod.PATCH, requestEntity, Void.class);
}

private ObjectMapper getObjectMapperWithHalModule() {
    if(objectMapperHal == null) {
        objectMapperHal = new ObjectMapper();
        objectMapperHal.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapperHal.registerModule(new Jackson2HalModule());
    }

    return objectMapperHal;
}
public void补丁(M theEntity,Integer entityId,String linkName,URI linkUri){
ObjectMapper ObjectMapper=getObjectMapperWithHalModule();
ObjectNode linkedNode=(ObjectNode)objectMapper.valueToTree(实体);
linkedNode.put(linkName,linkUri.getPath());
HttpEntity requestEntity=新的HttpEntity(linkedNode);
交换(uri+“/”+entityId,HttpMethod.PATCH,requestEntity,Void.class);
}
私有对象映射器getObjectMapperWithHalModule(){
if(objectMapperHal==null){
objectMapperHal=新的ObjectMapper();
configure(在未知属性上反序列化feature.FAIL,false);
registerModule(新Jackson2HalModule());
}
返回objectMapperHal;
}

请随意查看这个示例的实现,我已经在java文件中添加了以下代码。这对我有用

String url="Your API URL";
RestTemplate restTemplate = new RestTemplate();
HttpClient httpClient = HttpClientBuilder.create().build();
restTemplate.setRequestFactory(new 
HttpComponentsClientHttpRequestFactory(httpClient));    
HttpHeaders reqHeaders = new HttpHeaders();
reqHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> requestEntity = new HttpEntity<String>(requestJson, reqHeaders);
ResponseEntity<String> responseEntity=restTemplate.exchange(url, HttpMethod.PATCH, 
requestEntity, String.class);
stringurl=“您的API url”;
RestTemplate RestTemplate=新RestTemplate();
HttpClient HttpClient=HttpClientBuilder.create().build();
restTemplate.setRequestFactory(新
HttpComponents客户端HttpRequestFactory(httpClient));
HttpHeaders reqHeaders=新的HttpHeaders();
reqHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity requestEntity=新的HttpEntity(requestJson,ReqHeader);
ResponseEntity ResponseEntity=restemplate.exchange(url,HttpMethod.PATCH,
requestEntity,String.class);
此外,还需要在pom.xml文件中添加以下依赖项

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

org.apache.httpcomponents
httpclient

要保存一些行,您可以在一行中执行RestTemplate初始化
新建RestTemplate(新的HttpComponentsClientHttpRequestFactory())
@adebasi您知道为什么需要这样做吗?我认为“this”的意思是您必须设置
HttpComponentsClientHttpRequestFactory
。这个命令()回答了你的问题。在2021年,WTF仍然是个问题。但是感谢您的解决方案:)通过包含关于为什么需要和/或为什么它是“修复程序”的上下文,这个答案可以得到显著改进。这是哪个版本的spring?下面是为什么必须包含
HttpComponents客户端HttpRequestFactory
:标准JDK HTTP库不支持HTTP修补程序。您需要使用Apache HttpComponents或OkHttp请求工厂进行springboot 2 its
.requestFactory(HttpComponentsClientHttpRequestFactory.class)
@DannyK感谢您指出Spring boot 2的配置方式。如果您使用Spring boot v2.3,那么如果您将依赖项添加到项目中,它将自动配置。
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>