В Интернете есть много вещей, как работать с 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 @SessionScoped public 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 @ViewScoped public 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 @ViewScoped public 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 Олега Вараксина в блоге « Мысли о разработке программного обеспечения» .