Вступление
Как вы уже знаете, есть два способа разработки веб-сервиса
- Простой протокол доступа к объектам (SOAP)
- Представительный государственный трансферт (REST)
Прежде чем приступить к созданию веб-службы на основе REST с использованием Apache CXF, посмотрим, что такое REST. REST — это не технология и, конечно, не какой-то стандарт. Это просто архитектурный стиль, который описывает, как написать веб-сервис определенным образом. Этот стиль был определен неким Роем Филдингом (кольцевые колокольчики? Да, вы правильно догадались, он один из архитекторов HTTP) в 2000 году. Главный герой архитектуры REST — это Ресурс, который может быть уникально идентифицирован с помощью Унифицированного идентификатора ресурса или URI . Состояние ресурса в любой данный момент времени представлено документом и называется представлением ресурса. Клиент может обновить состояние ресурса, передав представление вместе с запросом. Новое представление теперь возвращается клиенту вместе с ответом. Представление содержит информацию в таких форматах, как html, xml, JSON и т. Д., Которые принимаются ресурсом. Ресурс, который придерживается правил архитектуры REST, называется ресурсом RESTfull, а веб-сервис, который придерживается этого правила, называется веб-сервисом RESTfull.
Создайте проект, содержащий ваш веб-сервис
Я обычно делаю свою веб-разработку в struts2 + spring, используя maven Strut2 стартовый архетип для создания своего веб-проекта. Чтобы использовать CXF в моем проекте, я добавляю следующие зависимости к своему POM
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>${cxf.version}</version></dependency><dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${cxf.version}</version></dependency><dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>${cxf.version}</version></dependency> |
Пользователи не maven могут найти подробности зависимостей, которые будут добавлены по следующей ссылке: http://cxf.apache.org/docs/using-cxf-with-maven.html . CXF можно скачать прямо здесь: http://cxf.apache.org/download.html
Как создать веб-сервис CXF RESTfull?
Предположим, вы хотите создать веб-сервис RESTfull, используя CXF для управления книгами на вашей личной книжной полке. Как правило, вы хотите выполнить следующие действия на книжной полке
- Добавить книгу
- Обновить информацию о книге
- Удалить книгу с полки
- Получить книгу
- Получить список книг
- Получить список книг по имени автора
Следующие шаги необходимы для создания такого сервиса
- Создайте BookVO, BookList (объект значения) для передачи в виде представления в запросе и ответе.
- Свяжите объекты с запросом и ответом.
- Создайте класс реализации службы для принятия запроса и генерации ответа.
- Регистрация вашего веб-сервиса с контейнером CXF.
- Разверните сервис в веб-контейнере.
- Создайте клиентов для вызова методов в службе.
Получение исходного кода для этого урока
Я передал исходные файлы для этого урока в SVN.
- Вы можете загрузить веб-приложение по адресу: http://subversion.assembla.com/svn/weblog4j/Weblog4jDemo/trunk
- Вы можете скачать клиент с: http://subversion.assembla.com/svn/weblog4j/DemoClient/trunk
Примечание. Оба проекта являются проектами ItelliJ maven, поэтому вы можете напрямую импортировать их в вашу среду IntelliJ или скопировать файлы вручную в другую среду IDE.
Создать BookVO (объект значения) для передачи в качестве представления в запросе и ответе.
Класс BookVO
|
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
|
package com.aranin.weblog4j.vo;import javax.xml.bind.annotation.XmlRootElement;import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;import java.io.Serializable;@XmlRootElement(name="Book")public class BookVO implements Serializable{private long bookId;private String bookName;private String author;public long getBookId() {return bookId;}public void setBookId(long bucketId) {this.bookId = bookId;}public String getBookName() {return bookName;}public void setBookName(String bookName) {this.bookName = bookName;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}} |
Класс BookList
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
package com.aranin.weblog4j.vo;import javax.xml.bind.annotation.XmlRootElement;import java.util.ArrayList;import java.util.List;@XmlRootElement(name="BookList")public class BookList {private List<BookVO> bookList;public List<BookVO> getBookList() {if(bookList == null){bookList = new ArrayList<BookVO>();}return bookList;}public void setBookList(List<BookVO> bookList) {this.bookList = bookList;}} |
Привязать объект данных, т.е. BookVO с запросом и ответом
Чтобы связать BookVO с запросом или ответом, его необходимо сериализовать в потоки XML или JSON. Сериализация должна выполняться с использованием одного из компонентов привязки данных. CXF использует JAXB для компонента привязки данных по умолчанию. JaXB использует аннотацию @XmlRootElement для сопоставления объекта данных с xml. Вы можете увидеть использование аннотации XmlRootElement в приведенном выше коде.
Создайте класс реализации сервиса для принятия запроса и генерации ответа.
Давайте посмотрим, как выглядит веб-сервис CXF RestFull. Мы создадим класс BookService, который будет выполнять операции добавления, обновления, удаления и получения на BookSelf.
Класс BookService
|
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
|
package com.aranin.weblog4j.services.rest;import com.aranin.weblog4j.hashdb.HashDB;import com.aranin.weblog4j.vo.BookVO;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.ws.rs.*;import javax.ws.rs.core.Response;import java.io.UnsupportedEncodingException;import java.net.URLDecoder;/** * Created by IntelliJ IDEA. * User: Niraj Singh * Date: 3/13/13 * Time: 3:58 PM * To change this template use File | Settings | File Templates. */public class BookService {protected final Logger log = LoggerFactory.getLogger(BookService.class); @POST @Path("/getbook/{name}") @Produces({"application/xml","application/json"}) @Consumes({"application/xml","application/json","application/x-www-form-urlencoded"}) public Response getBucket(@PathParam("name") String name) { log.debug("name : " + name); BookVO bookVO = null; try { bookVO = HashDB.getBook(URLDecoder.decode(name, "UTF-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } if(bookVO == null){ return Response.status(Response.Status.BAD_REQUEST).build(); }else{ return Response.ok(bookVO).build(); } } @POST @Path("/addbook") @Produces({"application/xml","application/json"}) @Consumes({"application/xml","application/json","application/x-www-form-urlencoded"}) public Response addBook(@FormParam("name") String bookName, @FormParam("author") String author) { log.debug("inside addBook"); BookVO bookVO = new BookVO(); bookVO.setBookName(bookName); bookVO.setAuthor(author); HashDB.insertBook(bookVO); if(HashDB.getBook(bookName) == null){ return Response.status(Response.Status.BAD_REQUEST).build(); }else{ return Response.ok(bookVO).build(); } }} |
Вы можете увидеть два метода в классе BookService getBook и addBook. Это сервисные методы для получения и добавления книги. Остальные методы удаления обновлений и т. Д. Могут быть написаны таким же образом. Теперь давайте посмотрим, что означают различные аннотации и вызов метода.
- @POST — это означает, что сервис получает только POST-запрос.
- @Path — это путь к веб-сервису. Таким образом, веб-сервис может быть вызван с использованием следующего Url <base_url> / bookservice / getbook / {name} для выборки, <base_url> / bookservice / addbook для добавления.
- @Produces — указывает тип сгенерированного ответа MIME. В нашем случае это и приложение / xml, и приложение / json.
- @Consumes — указывает MIME-тип запроса, который может использовать этот сервис.
Регистрация вашего веб-сервиса с контейнером CXF.
Одна из замечательных особенностей CXF заключается в том, что он использует конфигурацию на основе пружины для регистрации своих конечных точек веб-службы, поэтому давайте создадим beans.xml в WEB-INF и настроим CXF в web.xml. Для этого сначала нам нужно подключить файл beans.xml для загрузки контейнером Spring.
|
1
2
3
4
|
<context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/beans.xml,/WEB-INF/applicationContext.xml</param-value></context-param> |
Во-вторых, загрузите реестр CXFServlet в web.xml.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
<servlet><servlet-name>CXFServlet</servlet-name><display-name>CXF Servlet</display-name><servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class><load-on-startup>2</load-on-startup></servlet><servlet-mapping><servlet-name>CXFServlet</servlet-name><url-pattern>/*</url-pattern></servlet-mapping> |
Теперь откройте ваш bean.xml и зарегистрируйте конечную точку книжного сервиса.
|
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
|
<?xml version="1.0" encoding="UTF-8"?> xsi:schemaLocation=" <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <jaxws:endpoint id="bookShelfService" implementor="com.aranin.weblog4j.services.BookShelfServiceImpl" address="/bookshelfservice" /> <bean id="bookserviceclass" class="com.aranin.weblog4j.services.rest.BookService"/> <jaxrs:server id="bookservice" address="/bookservice"> <jaxrs:serviceBeans> <ref bean="bookserviceclass" /> </jaxrs:serviceBeans> </jaxrs:server></beans> |
Теперь ваш веб-сервис готов. Создайте свое веб-приложение и разверните его в любом контейнере сервлетов.
Создание клиента для вашего веб-сервиса
Клиенты могут быть созданы разными способами, я использовал Apache Http Components для написания своего клиента. Библиотеки можно найти по адресу http://hc.apache.org/httpclient-3.x/ .
Пользователь Maven может вытащить банку компонентов Http, используя следующие
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
<dependency><groupId>commons-httpclient</groupId><artifactId>commons-httpclient</artifactId><version>3.1</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.1.3</version><scope>compile</scope></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId><version>4.1.3</version><scope>compile</scope></dependency> |
Теперь, чтобы вызвать веб-сервис, я создал класс утилит под названием DemoRestClient.
|
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
package com.aranin.weblog4j.client;import com.aranin.weblog4j.vo.BookVO;import org.apache.commons.httpclient.Header;import org.apache.commons.httpclient.HttpClient;import org.apache.commons.httpclient.methods.PostMethod;import java.net.URLEncoder;/** * Created by IntelliJ IDEA. * User: Niraj Singh * Date: 3/13/13 * Time: 4:15 PM * To change this template use File | Settings | File Templates. */public class DemoRestClient { public static void main(String[] args){ DemoRestClient restClient = new DemoRestClient(); try { //restClient.addBook("Naked Sun", "Issac Asimov"); restClient.getBook("Naked Sun"); } catch (Exception e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } } public BookVO getBook(String bookName) throws Exception { String output = null; try{ url = url + URLEncoder.encode(bookName, "UTF-8"); HttpClient client = new HttpClient(); PostMethod mPost = new PostMethod(url); client.executeMethod( mPost ); Header mtHeader = new Header(); mtHeader.setName("content-type"); mtHeader.setValue("application/x-www-form-urlencoded"); mtHeader.setName("accept"); mtHeader.setValue("application/xml"); mPost.addRequestHeader(mtHeader); client.executeMethod(mPost); output = mPost.getResponseBodyAsString( ); mPost.releaseConnection( ); System.out.println("out : " + output); }catch(Exception e){ throw new Exception("Exception in retriving group page info : " + e); } return null; } public void addBook(String bookName, String author) throws Exception { String output = null; try{ HttpClient client = new HttpClient(); PostMethod mPost = new PostMethod(url); mPost.addParameter("name", "Naked Sun"); mPost.addParameter("author", "Issac Asimov"); Header mtHeader = new Header(); mtHeader.setName("content-type"); mtHeader.setValue("application/x-www-form-urlencoded"); mtHeader.setName("accept"); mtHeader.setValue("application/xml"); //mtHeader.setValue("application/json"); mPost.addRequestHeader(mtHeader); client.executeMethod(mPost); output = mPost.getResponseBodyAsString( ); mPost.releaseConnection( ); System.out.println("output : " + output); }catch(Exception e){ throw new Exception("Exception in adding bucket : " + e); } }} |
Запустите этот клиент, чтобы увидеть выходные данные вашего веб-сервиса. Прямо сейчас он отправит xmloutput, поскольку заголовок подтверждения ответа — «application / xml». Вы можете изменить его на application / json, чтобы получить вывод json.
Это все люди. Это очень простое введение в разработку веб-сервиса RestFull с использованием apache CXF, есть еще много чего, что можно исследовать. Счастливого пути, до свидания. Пожалуйста, оставьте некоторые комментарии, и если вы прочитаете это, чтобы вдохновить меня.