This article introduces the use of the Jersey client to request Spring Boot (RESTFul) service, and shares it with you, as follows:
Jersey client gets the Client object instance encapsulation:
@Service("jerseyPoolingClient") public class JerseyPoolingClientFactoryBean implements FactoryBean<Client>, InitializingBean, DisposableBean{ /** * The Client interface is the basic interface of the REST client and is used to communicate with the REST server. Client is defined as a heavyweight object that manages the various objects at the bottom of the client communication, such as connectors, parsers, etc. Therefore, it is not recommended to generate a large number of Client instances in the application. This is necessary in development. In addition, this interface requires that the instance must be closed, otherwise it will cause memory leakage*/ private Client client; /** * The maximum number of connections for a client, default is 2000 */ private int maxTotal = 2000; /** * The default maximum number of connections per route*/ private int defaultMaxPerRoute = 1000; private ClientConfig clientConfig; public JerseyPoolingClientFactoryBean() { } /** * Constructor with configuration* @param clientConfig */ public JerseyPoolingClientFactoryBean(ClientConfig clientConfig) { this.clientConfig = clientConfig; } public JerseyPoolingClientFactoryBean(int maxTotal, int defaultMaxPerRoute) { this.maxTotal = maxTotal; this.defaultMaxPerRoute = defaultMaxPerRoute; } /** * attention: * Details: Release Client resources when container is destroyed* @author chhliu */ @Override public void destroy() throws Exception { this.client.close(); } /** * * attention: * Details: Initialize the Client object in the form of a connection pool* @author chhliu */ @Override public void afterPropertiesSet() throws Exception { // If the constructor with ClientConfig is not used, the instance of the class is null, and the default configuration is initialized if(this.clientConfig == null){ final ClientConfig clientConfig = new ClientConfig(); // Connection pool management instance, this class is thread-safe and supports multiple concurrent operations PoolingHttpClientConnectionManager pcm = new PoolingHttpClientConnectionManager(); pcm.setMaxTotal(this.maxTotal); pcm.setDefaultMaxPerRoute(this.defaultMaxPerRoute); clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, pcm); /* * When using Jersey to request Spring Boot service, Spring Boot uses Jackson to parse JSON by default *, while Jersey uses MOXy to parse JSON by default. When Jersey Client wants Spring Boot service to request resources, * This difference will cause the server and client to convert POJO differently, resulting in deserialization errors* Therefore, you need to register the Jackson feature in the Client's Config instance here*/ clientConfig.register(JacksonFeature.class); // Use the configuration Apache connector, the default connector is HttpUrlConnector clientConfig.connectorProvider(new ApacheConnectorProvider()); client = ClientBuilder.newClient(clientConfig); }else{ // Use ClientConfig in the constructor to initialize the Client object client = ClientBuilder.newClient(this.clientConfig); } } /** * attention: * Details: Returns the Client object. If the object is null, create a default Client * @author chhliu */ @Override public Client getObject() throws Exception { if(null == this.client){ return ClientBuilder.newClient(); } return this.client; } /** * attention: * Details: Get the type of the Client object* @author chhliu */ @Override public Class<?> getObjectType() { return (this.client == null ? Client.class : this.client.getClass()); } /** * attention: * Details: Whether the Client object is a singleton, default to a singleton* @author chhliu */ @Override public boolean isSingleton() { return true; } }Requesting the encapsulation of Spring Boot service:
@Component("jerseyClient") public class JerseyClient { @Resource(name="jerseyPoolingClient") private Client client; /** * attention: * Details: Query the object through id* @author chhliu */ public ResultMsg<GitHubEntity> getResponseById(final String id) throws JsonProcessingException, IOException{ WebTarget webTarget = client.target("http://localhost:8080").path("/github/get/user/"+id); Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON); GenericType<ResultMsg<GitHubEntity>> genericType = new GenericType<ResultMsg<GitHubEntity>>(){}; Response response = invocationBuilder.get(); if(response.getStatus() == 200){ /* * When the readEntity method is called, the program will automatically release the connection* Even if the readEntity method is not called and the generic type object is returned directly, the underlying layer will still release the connection*/ return response.readEntity(genericType); }else{ ResultMsg<GitHubEntity> res = new ResultMsg<GitHubEntity>(); res.setErrorCode(String.valueOf(response.getStatus())); res.setErrorMsg(response.getStatusInfo().toString()); res.setOK(false); return res; } } /** * attention: * Details: Pagination query* @author chhliu */ public ResultMsg<Pager<GitHubEntity>> getGithubWithPager(final Integer pageOffset, final Integer pageSize, final String orderColumn){ WebTarget webTarget = client.target("http://localhost:8080").path("/github/get/users/page") .queryParam("pageOffset", pageOffset) .queryParam("pageSize", pageSize) .queryParam("orderColumn", orderColumn); // Note that if the media type here is MediaType.APPLICATION_JSON, then the corresponding parameter in the service must be preceded by @RequestBody Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON); GenericType<ResultMsg<Pager<GitHubEntity>>>> genericType = new GenericType<ResultMsg<Pager<GitHubEntity>>>(){}; Response response = invocationBuilder.get(); if(response.getStatus() == 200){ return response.readEntity(genericType); }else{ ResultMsg<Pager<GitHubEntity>> res = new ResultMsg<Pager<GitHubEntity>>(); res.setErrorCode(String.valueOf(response.getStatus())); res.setErrorMsg(response.getStatusInfo().toString()); res.setOK(false); return res; } } /** * attention: * Details: Query based on username* @author chhliu */ public ResultMsg<List<GitHubEntity>> getResponseByUsername(final String username) throws JsonProcessingException, IOException{ WebTarget webTarget = client.target("http://localhost:8080").path("/github/get/users/"+username); Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON); GenericType<ResultMsg<List<GitHubEntity>>> genericType = new GenericType<ResultMsg<List<GitHubEntity>>>(){}; Response response = invocationBuilder.get(); if(response.getStatus() == 200){ return response.readEntity(genericType); }else{ ResultMsg<List<GitHubEntity>>> res = new ResultMsg<List<GitHubEntity>>(); res.setErrorCode(String.valueOf(response.getStatus())); res.setErrorMsg(response.getStatusInfo().toString()); res.setOK(false); return res; } } /** * attention: * Details: Delete a record based on id* @author chhliu */ public ResultMsg<GitHubEntity> deleteById(final String id) throws JsonProcessingException, IOException{ WebTarget target = client.target("http://localhost:8080").path("/github/delete/"+id); GenericType<ResultMsg<GitHubEntity>> genericType = new GenericType<ResultMsg<GitHubEntity>>(){}; Response response = target.request().delete(); if(response.getStatus() == 200){ return response.readEntity(genericType); }else{ ResultMsg<GitHubEntity> res = new ResultMsg<GitHubEntity>(); res.setErrorCode(String.valueOf(response.getStatus())); res.setErrorMsg(response.getStatusInfo().toString()); res.setOK(false); return res; } } /** * attention: * Details: Update a record* @author chhliu */ public ResultMsg<GitHubEntity> update(final GitHubEntity entity) throws JsonProcessingException, IOException{ WebTarget target = client.target("http://localhost:8080").path("/github/put"); GenericType<ResultMsg<GitHubEntity>> genericType = new GenericType<ResultMsg<GitHubEntity>>(){}; Response response = target.request().buildPut(Entity.entity(entity, MediaType.APPLICATION_JSON)).invoke(); if(response.getStatus() == 200){ return response.readEntity(genericType); }else{ ResultMsg<GitHubEntity> res = new ResultMsg<GitHubEntity>(); res.setErrorCode(String.valueOf(response.getStatus())); res.setErrorMsg(response.getStatusInfo().toString()); res.setOK(false); return res; } } /** * attention: * Details: Insert a record* @author chhliu */ public ResultMsg<GitHubEntity> save(final GitHubEntity entity) throws JsonProcessingException, IOException{ WebTarget target = client.target("http://localhost:8080").path("/github/post"); GenericType<ResultMsg<GitHubEntity>> genericType = new GenericType<ResultMsg<GitHubEntity>>(){}; Response response = target.request().buildPost(Entity.entity(entity, MediaType.APPLICATION_JSON)).invoke(); if(response.getStatus() == 200){ return response.readEntity(genericType); }else{ ResultMsg<GitHubEntity> res = new ResultMsg<GitHubEntity>(); res.setErrorCode(String.valueOf(response.getStatus())); res.setErrorMsg(response.getStatusInfo().toString()); res.setOK(false); return res; } } } Detailed explanation of Jersey client interface
1 Client interface
Creating a Client instance is constructed through ClientBuilder. Usually a ClientConfig instance is used as a parameter. If we use Client client = ClientBuilder.newClient() to create a Client instance, we will create a Client instance every time, but the instance is a heavyweight object. Therefore, it is recommended to use HTTP connection pooling to manage connections, rather than creating a Client object every time we request. For specific connection pool management methods, see the code example above.
2 WebTarget interface
The WebTarget interface is an interface that implements resource positioning for REST clients. Through the WebTarget interface, we can define the specific address of the requested resource, query parameters and media type information, etc. We can complete the configuration of a WebTarget instance through a method chain, but it should be noted that although the usage method of WebTarget is very similar to the method chain of StringBuffer, it is essentially different. The method chain of WebTarget must set the return value of the method as a handle to the subsequent process. What does this mean? See the following examples:
Example 1: StringBuffer method chain example
StringBuffer sb = new StringBuffer("lch"); sb.append("hello"); sb.append("world"); sb.append("hello").append("world"); // This method is the same as the above two lines of code.Example 2: WebTarget method chain example
// Use a one-line code method chain to instantiate WebTarget WebTarget webTarget = client.target("http://localhost:8080"); webTarget.path("/github/get/users/page") .queryParam("pageOffset", pageOffset) .queryParam("pageSize", pageSize) .queryParam("orderColumn", orderColumn); // Here is the use of method chains to instantiate WebTarget webTarget.path("/github/get/users/page"); webTarget.queryParam("pageOffset", pageOffset); webTarget.queryParam("pageSize", pageSize); // The results of the above two instantiation methods are very different. The above instantiation method is OK, there is no problem, but the following instantiation method has problems. In the following instantiation method, each row will generate a // new WebTarget object. The original WebTarget did not play any role. After all, the instances of each row are different. If we want to instantiate it in multiple rows, we must provide a handle for the return of each method. The method is as follows: WebTarget target = client.target("http://localhost:8080"); WebTarget pathTarget = target.path("/github/get/users/page"); WebTarget paramTarget = pathTarget.queryParam("pageOffset", pageOffset); // When using it last, use the last WebTarget instance object 3 Invocation interface
The Invocation interface is an interface that initiates a request to the REST server after completing resource positioning configuration. The request includes two methods: synchronization and asynchronous. It is defined by the Builder interface inside the Invocation interface. The Builder interface inherits the synchronization interface SyncInvoker. The examples of asynchronous calls are as follows:
Future<ResultMsg<List<GitHubEntity>>> response = invocationBuilder.async().get(genericType); if(response.isDone()){ return response.get(); } The Invocation.Builder interface instance executes GET and POST requests to submit queries and creates respectively. By default, the return type of HTTP method call is Response type, and it also supports the return value of generic type. In the above example, we used a large number of generics, so we will not explain too much here.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.