This article is for the blogger to study notes, the content comes from the Internet, if there is infringement, please contact delete.
Personal Note: github.com/dbses/TechN…
01 | build a RESTful style Web services
Understand RESTful architectural styles
REST (Representational State Transfer) is an architectural style that treats an access point on the server side as a resource and uses standard HTTP methods over transport protocols, such as the most common GET, PUT, POST, and DELETE.
The following table shows some concrete examples of RESTful styles:
There are also industry conventions for RESTful design of HTTP endpoints. In the case of the Account domain entity, if we think of it as a resource, the root node of the HTTP endpoint is usually named in the plural form, “/accounts.”
When designing RESTful apis, the following figure shows some of the differences between RESTful and non-restful apis for common CRUD operations.
Use basic annotations
- @RestController
The @RestController annotation, inherited from the @Controller annotation in Spring MVC, is a RESTful HTTP endpoint and automatically serializes/deserializes HTTP requests and responses using JSON.
- @GetMapping
The @getMapping annotation is defined very similarly to @RequestMapping, except that by default requestMethod.get specifies the HTTP method.
Controls the input of the request
- @PathVariable
The @pathVariable annotation is used to retrieve path parameters. Get the value of the {id} parameter from a path of the form url/{id}.
- @RequestParam
The @requestParam annotation is also used to get the parameters in the request, but it’s geared towards things like urls? The path id=XXX.
- @RequestMapping
In HTTP, the Content-type attribute is used to specify what type of content is transferred. We can set this attribute in the @requestMapping annotation in Produces.
- @RequestBody
The @requestbody annotation is used to handle encoded content whose content-type is application/json. The @requestbody annotation binds the json string in the RequestBody to the corresponding javabeans.
02 | how to use RestTemplate consumption RESTful services?
Create the RestTemplate
If we want to create a RestTemplate object, the simplest and most common way is to simply new an instance of the class, as shown in the following code:
@Bean
public RestTemplate restTemplate(a){
return new RestTemplate();
}
Copy the code
Let’s look at the no-argument constructor for RestTemplate, as shown in the following code:
public RestTemplate(a) {
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter(false));
this.messageConverters.add(new SourceHttpMessageConverter<>());
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
// Omit other code to add HttpMessageConverter
}
Copy the code
The no-argument constructor of RestTemplate adds a number of HttpMessageConverter objects for message transformation.
RestTemplate has another, more powerful, parameter constructor, as shown in the following code:
public RestTemplate(ClientHttpRequestFactory requestFactory) {
this(a); setRequestFactory(requestFactory); }Copy the code
Can be used to set HTTP request timeout and other properties, as shown in the following code:
@Bean
public RestTemplate customRestTemplate(a){
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
// Connection request timeout
httpRequestFactory.setConnectionRequestTimeout(3000);
// Connection timeout time
httpRequestFactory.setConnectTimeout(3000);
httpRequestFactory.setReadTimeout(3000);
return new RestTemplate(httpRequestFactory);
}
Copy the code
Use RestTemplate to access the Web service
- GET
public <T> T getForObject(URI url, Class<T> responseType)
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables)
public <T> T getForObject(String url, Class
responseType, Map
uriVariables)
,>
Copy the code
You can also use the getForEntity method to return a ResponseEntity object.
- POST
Order order = new Order();
order.setOrderNumber("Order0001");
order.setDeliveryAddress("DemoAddress");
ResponseEntity<Order> responseEntity = restTemplate.postForEntity("http://localhost:8082/orders", order, Order.class);
return responseEntity.getBody();
Copy the code
PostForObject operates similarly.
- exchange
ResponseEntity<Order> result = restTemplate.exchange("http://localhost:8082/orders/{orderNumber}", HttpMethod.GET, null, Order.class, orderNumber);
Copy the code
// Set the HTTP Header
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
// Set access parameters
HashMap<String, Object> params = new HashMap<>();
params.put("orderNumber", orderNumber);
// Set the request Entity
HttpEntity entity = new HttpEntity<>(params, headers);
ResponseEntity<Order> result = restTemplate.exchange(url, HttpMethod.GET, entity, Order.class);
Copy the code
RestTemplate other usage tips
- Specify message converter
If we want to load the Gson-enabled GsonHttpMessageConverter into the RestTemplate, we can use the code shown below.
@Bean
public RestTemplate restTemplate(a) { List<HttpMessageConverter<? >> messageConverters =newArrayList<HttpMessageConverter<? > > (); messageConverters.add(new GsonHttpMessageConverter());
RestTemplate restTemplate = new RestTemplate(messageConverters);
return restTemplate;
}
Copy the code
- Setting up interceptors
The most typical application scenario for this is to add load balancing to the RestTemplate in the Spring Cloud via the @loadBalanced annotation. We can find the following code in the LoadBalanceAutoConfiguration automatic configuration class.
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return new RestTemplateCustomizer() {
@Override
public void customize(RestTemplate restTemplate) {
List<ClientHttpRequestInterceptor> list = newArrayList<>( restTemplate.getInterceptors()); list.add(loadBalancerInterceptor); restTemplate.setInterceptors(list); }}; }Copy the code
- Handle exceptions
When the request status code does not return 200, the RestTemplate by default throws an exception and interrupts the rest of the operation. If we do not want to do this, we need to override the default ResponseErrorHandler. The sample code structure is as follows:
RestTemplate restTemplate = new RestTemplate();
ResponseErrorHandler responseErrorHandler = new ResponseErrorHandler() {
@Override
public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
return true;
}
@Override
public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {
// Add custom exception handling code}}; restTemplate.setErrorHandler(responseErrorHandler);Copy the code
03 | RestTemplate remote calls the principle
The class layer structure of RestTemplate looks like this:
The class layer structure is clearly divided into two branches, with the left branch providing implementation mechanisms related to HTTP requests, and the right branch providing RESTful entry points using object-oriented interfaces and abstract classes to achieve the convergence of these two parts of functionality.
InterceptingHttpAccessor
It is an abstract class that contains core variables as shown in the following code:
public abstract class InterceptingHttpAccessor extends HttpAccessor {
private final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
private volatileClientHttpRequestFactory interceptingRequestFactory; ... }Copy the code
Interceptors are responsible for setting up and managing request interceptors; InterceptingRequestFactory responsible for creating the HTTP client requests.
InterceptingHttpAccessor also has a parent class HttpAccessor:
public abstract class HttpAccessor {
private ClientHttpRequestFactory requestFactory = newSimpleClientHttpRequestFactory(); ... }Copy the code
Create SimpleClientHttpRequestFactory HttpAccessor as ClientHttpRequestFactory system default.
RestOperations
The RestOperations interface is defined as follows:
public interface RestOperations {
<T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException;
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException;
<T> T postForObject(String url, @Nullable Object request, Class<T> responseType,Object... uriVariables) throws RestClientException;
void put(String url, @Nullable Object request, Object... uriVariables) throws RestClientException;
void delete(String url, Object... uriVariables) throws RestClientException;
<T> ResponseEntity<T> exchange(String url, HttpMethod method, @NullableHttpEntity<? > requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException; ... }Copy the code
RestTemplate core execution process
A good place to start is with an Exchange method with multiple requests, defined as follows:
@Override
public <T> ResponseEntity<T> exchange(String url,
HttpMethod method,
@NullableHttpEntity<? > requestEntity, Class<T> responseType, Object... uriVariables)
throws RestClientException {
// Build request callback
RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
// Build the response body extractor
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
// Perform the remote call
return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
}
Copy the code
The execute method is defined as follows:
@Override
@Nullable
public <T> T execute(String url,
HttpMethod method,
@Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor,
Object... uriVariables) throws RestClientException {
URI expanded = getUriTemplateHandler().expand(url, uriVariables);
return doExecute(expanded, method, requestCallback, responseExtractor);
}
Copy the code
The doExecute method is defined as follows:
protected <T> T doExecute(URI url,
@Nullable HttpMethod method,
@Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor)
throws RestClientException {
Assert.notNull(url, "URI is required");
Assert.notNull(method, "HttpMethod is required");
ClientHttpResponse response = null;
try {
// 1. Create request object
ClientHttpRequest request = createRequest(url, method);
if(requestCallback ! =null) {
// Perform a callback to the request
requestCallback.doWithRequest(request);
}
// 2. Get the result of the call
response = request.execute();
// 3. Process the result of the call
handleResponse(url, method, response);
// Extract data from results
return(responseExtractor ! =null ? responseExtractor.extractData(response) : null);
} catch(IOException ex) { String resource = url.toString(); String query = url.getRawQuery(); resource = (query ! =null ? resource.substring(0, resource.indexOf('? ')) : resource);
throw new ResourceAccessException("I/O error on "
+ method.name() +
" request for \"" + resource + "\","
+ ex.getMessage(), ex);
} finally {
if(response ! =null) { response.close(); }}}Copy the code