我正在编写 JUnit 测试,通过
RestTemplate
调用我的应用程序。我已经成功实现了 GET、POST 和 PUT,但无法运行 PATCH(尽管它在客户端发送 URL 时起作用)。例如,POST 使用以下代码运行:
RestTemplate restTemplate = new RestTemplate();
ProductModel postModel = restTemplate.postForObject(TestBase.URL + URL, pModel, ProductModel.class);
但是当我尝试调用restTemplate.patchForObject()(我在网上找到的)时,STS 返回一个错误,指出该函数未定义。我因此使用了这个:
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<MessageModel> retval = restTemplate.exchange("http://localhost:8080/products/batchUpdateProductPositions",
HttpMethod.PATCH, new HttpEntity<ProductPositionListModel>(pps), MessageModel.class);
它可以编译,但给我一个错误:
I/O Error on PATCH request for "http://localhost:8080/products/batchUpdateProductPositions": Invalid HTTP method: PATCH
在应用程序中,我在控制器类中定义了操作:
@RequestMapping(value = "/batchUpdateProductPositions", method = RequestMethod.PATCH)
public MessageModel batchUpdatePosition(
@RequestBody ProductPositionListModel productPositionList)
throws Exception {
try {
return productService.batchUpdatePosition(productPositionList);
} catch (Exception e) {
我在“try”块内的 return 语句上放置了一个断点,但当我在调试下运行它时它从未跳闸。
谁能告诉我我在哪里绊倒了?
默认情况下
RestTemplate
使用标准 JDK HttpURLConnection
HTTP 客户端发出请求。该客户端不支持PATCH
方法。您可以通过客户端工厂将 RestTemplate
配置为使用其他 HTTP 客户端,例如 HttpComponentsClientHttpRequestFactory
或 OkHttpClientHttpRequestFactory
。
HttpClient client = HttpClients.createDefault();
RestTemplate template= new RestTemplate();
template.setRequestFactory(new HttpComponentsClientHttpRequestFactory(client));
您还需要添加适当的依赖项,例如
org.apache.httpcomponents:httpclient:$version
(如果是 HTTP 组件客户端)。
我发现了一个与 JUnit 代码的其余部分保持一致的解决方案。使用 postForObject(),您可以传入本例中您需要的 HTTP 方法:
MessageModel pModel = restTemplate.postForObject(TestBase.URL + URL + "/batchUpdateProductPositions?_method=patch",
pps, MessageModel.class);
运行正确。不能说是否有我没有注意到的副作用。
这对我有用,可以使用 RestTemplate 执行 PATCH 请求:
RestTemplate restTemplate = new RestTemplate();
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setConnectTimeout(timeout);
httpRequestFactory.setReadTimeout(timeout);
restTemplate.setRequestFactory(httpRequestFactory);
现在将此restTemplate 与exchange() 一起使用。
所需的依赖项
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
试试这个:
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
//...
RestTemplate rest = new RestTemplate(new HttpComponentsClientHttpRequestFactory())
//Now make the PATCH call using Exchange
ResponseEntity<Map<String, Object>> response = rest.exchange(api, HttpMethod.PATCH, request, responseType);
不要忘记将其添加到您的依赖项中:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.4.1</version>
</dependency>
这个解决方案
MessageModel pModel = restTemplate.postForObject(TestBase.URL + URL + "/batchUpdateProductPositions?_method=patch",pps, MessageModel.class);
如果您使用 Post 方法(
@PostMapping
),这很有用,如果您想使用 Patch 方法(@PatchMapping
),试试这个:
restTemplate.patchForObject("http://localhost:8080/products/batchUpdateProductPositions", requestEntity, String.class);
WebClient
提供了 RestTemplate
的现代替代方案,有效支持同步和异步以及流场景。您可以使用 WebClient 来实现此功能。
配置
WebClient
@Configuration
public class WebConfig {
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
}
然后就可以调用方法了
//Constructor Injection
public YourClassName(WebClient.Builder webClientBuilder) {
this.webClientBuilder = webClientBuilder;
}
MessageModel response = webClientBuilder.build()
.patch()
.uri("http://localhost:8080/products/batchUpdateProductPositions")
.contentType(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(MessageModel.class)
.block();
pom.xml 的依赖项
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
使用以下代码来解决这个问题,
在
pom.xml
,中添加以下依赖项
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>
<dependency>
从上述依赖项的 jar 文件中导入
CloseableHttpClient
和 HttpClients
。
要使用
HTTP Patch
发出RestTemplate
请求,以下配置是必需的,对于其他HTTP
调用,您可以忽略它。
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
@Bean
public RestTemplate restTemplate() {
LOGGER.info("restTemplate Bean has bean created");
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
RestTemplate restTemplate = new RestTemplate(factory);
return restTemplate;
}
在请求类中使用以下代码,
ResponseEntity<Object> response = restTemplate.exchange(url, HttpMethod.PATCH, requestEntity, Object.class);