В Интернете есть много вещей, как работать с RESTful Client API. Это основы. Но даже если предмет кажется тривиальным, существуют препятствия, особенно для начинающих.
В этом посте я постараюсь обобщить мои ноу-хау, как я это делал в реальных проектах. Я обычно использую Джерси (эталонная реализация для создания сервисов RESTful). Смотрите, например, мой другой пост . В этом посте я назову реальный удаленный сервис из бинов JSF. Давайте напишем сессионный компонент RestClient.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
package com.cc.metadata.jsf.controller.common;import com.sun.jersey.api.client.Client;import com.sun.jersey.api.client.ClientResponse;import com.sun.jersey.api.client.WebResource;import java.io.Serializable;import javax.annotation.PostConstruct;import javax.faces.bean.ManagedBean;import javax.faces.bean.SessionScoped;import javax.faces.context.FacesContext;/** * This class encapsulates some basic REST client API. */@ManagedBean@SessionScopedpublic class RestClient implements Serializable { private transient Client client; public String SERVICE_BASE_URI; @PostConstruct protected void initialize() { FacesContext fc = FacesContext.getCurrentInstance(); SERVICE_BASE_URI = fc.getExternalContext().getInitParameter('metadata.serviceBaseURI'); client = Client.create(); } public WebResource getWebResource(String relativeUrl) { if (client == null) { initialize(); } return client.resource(SERVICE_BASE_URI + relativeUrl); } public ClientResponse clientGetResponse(String relativeUrl) { WebResource webResource = client.resource(SERVICE_BASE_URI + relativeUrl); return webResource.accept('application/json').get(ClientResponse.class); }} |
В этом классе мы получили базовый URI службы, который указан (настроен) в файле web.xml.
|
1
2
3
4
|
<context-param> <param-name>metadata.serviceBaseURI</param-name></context-param> |
Кроме того, мы написали два метода для получения удаленных ресурсов. Мы намерены получать ресурсы в формате JSON и преобразовывать их в объекты Java. Следующий bean-компонент демонстрирует, как выполнить эту задачу для запросов GET. Компонент HistoryBean преобразует полученный JSON в объект Document с помощью GsonConverter. Последние два класса не будут показаны здесь (они не имеют значения). Document — это простой POJO, а GsonConverter — это одиночный экземпляр, который оборачивает Gson .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
package com.cc.metadata.jsf.controller.history;import com.cc.metadata.jsf.controller.common.RestClient;import com.cc.metadata.jsf.util.GsonConverter;import com.cc.metadata.model.Document;import com.sun.jersey.api.client.ClientResponse;import java.io.Serializable;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import javax.annotation.PostConstruct;import javax.faces.bean.ManagedBean;import javax.faces.bean.ManagedProperty;import javax.faces.bean.ViewScoped;/** * Bean getting history of the last extracted documents. */@ManagedBean@ViewScopedpublic class HistoryBean implements Serializable { @ManagedProperty(value = '#{restClient}') private RestClient restClient; private List<Document> documents; private String jsonHistory; public List<Document> getDocuments() { if (documents != null) { return documents; } ClientResponse response = restClient.clientGetResponse('history'); if (response.getStatus() != 200) { throw new RuntimeException('Failed service call: HTTP error code : ' + response.getStatus()); } // get history as JSON jsonHistory = response.getEntity(String.class); // convert to Java array / list of Document instances Document[] docs = GsonConverter.getGson().fromJson(jsonHistory, Document[].class); documents = Arrays.asList(docs); return documents; } // getter / setter ...} |
Следующий компонент демонстрирует, как связаться с удаленным сервисом через POST. Мы намерены отправить содержимое загруженного файла. Я использую компонент FileUpload в PrimeFaces, чтобы содержимое можно было извлечь как InputStream из параметра слушателя FileUploadEvent. Здесь это не важно, вы также можете использовать любые другие веб-фреймворки для получения содержимого файла (также как байтовый массив). Более важно увидеть, как работать с клиентскими классами RESTful FormDataMultiPart и FormDataBodyPart.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
package com.cc.metadata.jsf.controller.extract;import com.cc.metadata.jsf.controller.common.RestClient;import com.cc.metadata.jsf.util.GsonConverter;import com.cc.metadata.model.Document;import com.sun.jersey.api.client.ClientResponse;import com.sun.jersey.api.client.WebResource;import com.sun.jersey.core.header.FormDataContentDisposition;import com.sun.jersey.multipart.FormDataBodyPart;import com.sun.jersey.multipart.FormDataMultiPart;import org.primefaces.event.FileUploadEvent;import java.io.IOException;import java.io.Serializable;import javax.faces.application.FacesMessage;import javax.faces.bean.ManagedBean;import javax.faces.bean.ManagedProperty;import javax.faces.bean.ViewScoped;import javax.faces.context.FacesContext;import javax.ws.rs.core.MediaType;/** * Bean for extracting document properties (metadata). */@ManagedBean@ViewScopedpublic class ExtractBean implements Serializable { @ManagedProperty(value = '#{restClient}') private RestClient restClient; private String path; public void handleFileUpload(FileUploadEvent event) throws IOException { String fileName = event.getFile().getFileName(); FormDataMultiPart fdmp = new FormDataMultiPart(); FormDataBodyPart fdbp = new FormDataBodyPart(FormDataContentDisposition.name('file').fileName(fileName).build(), event.getFile().getInputstream(), MediaType.APPLICATION_OCTET_STREAM_TYPE); fdmp.bodyPart(fdbp); WebResource resource = restClient.getWebResource('extract'); ClientResponse response = resource.accept('application/json').type(MediaType.MULTIPART_FORM_DATA).post( ClientResponse.class, fdmp); if (response.getStatus() != 200) { throw new RuntimeException('Failed service call: HTTP error code : ' + response.getStatus()); } // get extracted document as JSON String jsonExtract = response.getEntity(String.class); // convert to Document instance Document doc = GsonConverter.getGson().fromJson(jsonExtract, Document.class); ... } // getter / setter ...} |
И последнее, но не менее важное: я хотел бы продемонстрировать, как отправить запрос GET с любой строкой запроса (параметры URL) Следующий метод запрашивает удаленную службу по URL-адресу, который выглядит как http: // somehost / metadata / extract? File = <некоторый путь к файлу>
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
public void extractFile() { WebResource resource = restClient.getWebResource('extract'); ClientResponse response = resource.queryParam('file', path).accept('application/json').get( ClientResponse.class); if (response.getStatus() != 200) { throw new RuntimeException('Failed service call: HTTP error code : ' + response.getStatus()); } // get extracted document as JSON String jsonExtract = response.getEntity(String.class); // convert to Document instance Document doc = GsonConverter.getGson().fromJson(jsonExtract, Document.class); ...} |
Ссылка: GET / POST с RESTful Client API от нашего партнера по JCG Олега Вараксина в блоге « Мысли о разработке программного обеспечения» .