- Мы используем Maven для сборки и тестирования некоторых успокоительных веб-сервисов на основе Spring.
- Затем мы используем плагин Maven Jetty для запуска веб-сервера и развертывания их на нем.
- Мы создаем базу данных в памяти и создаем схему
- Наконец, мы запускаем все интеграционные тесты в отдельном каталоге \ src \ integratest \ java
Структура кода
Выполнение примера
Полный код размещен на Google Code. Используйте следующие команды, чтобы проверить и запустить его. Убедитесь, что на порте 8080 ничего не работает, прежде чем запускать тесты.
1
2
3
|
svn co https: //designbycontract .googlecode.com /svn/trunk/examples/maven/spring-rest-example cd spring-rest-example mvn clean install -Pit,jetty |
Вы можете увидеть полную сборку на следующем экземпляре Jenkins, размещенном в Cloudbee. https://designbycontract.ci.cloudbees.com/job/spring-rest-example/
Результаты запуска примера
- Испытания в стандартной тестовой структуре maven проводятся, как обычно, на этапе модульных испытаний.
- Запущен веб-сервер Jetty
- Война, содержащая веб-сервер, развернута на сервере
- База данных hsqldb в памяти запущена и схема создана.
- Тесты в каталоге \ src \ integratest \ java выполняются на этапе тестирования интеграции.
- Сервер выключен.
Как создать класс Spring Service
Торговый сервис очень прост. Он использует репозиторий для создания и поиска сделок. Я не включил исключения, чтобы сделать все как можно более простым. Единственная хитрость здесь — добавить аннотацию @Service, иначе это прямая Java.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
@Service public class SimpleTradeService implements TradeService { @Autowired TradeRepository tradeRepository; public SimpleTradeService(TradeRepository tradeRepository) { this .tradeRepository = tradeRepository; } @Override public Long createTrade(Trade t) { Long id = tradeRepository.createTrade(t); return id; } @Override public Trade getTradeById(Long id) { return tradeRepository.getTradeById(id); } |
Как создать класс репозитория базы данных
Вышеуказанный сервис использует торговый репозиторий для создания и поиска сделок. Мы используем класс Spring HibernateDaoSupoort, чтобы создать этот класс и упростить его. Расширяя этот класс, нам просто нужно создать наш класс торговых объектов и определить детали нашей базы данных в весеннем конфиге. Все остальные детали позаботятся об этом.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
public class HibernateTradeRepository extends HibernateDaoSupport implements TradeRepository{ @Override public Trade getTradeByReference(String reference) { throw new RuntimeException(); } @Override public Long createTrade(Trade trade) { return (Long) getHibernateTemplate().save(trade); } @Override public Trade getTradeById(Long id) { return getHibernateTemplate().get(Trade. class , id); } } |
Как создать базу данных Trade Class
Мы используем стандартные аннотации JPA для определения торгового объекта нашей базы данных.
1
2
3
4
|
@Entity public class Trade { @Id private long id; |
Аннотация @Entity помечает объект как объект базы данных. Аннотация @Id показывает, какое поле мы хотим использовать в качестве первичного ключа нашей таблицы. Для остальных полей мы используем поведение по умолчанию, поэтому никаких других аннотаций не требуется.
Как настроить базу данных
Для этого примера мы будем использовать Hsqldb для создания нашей базы данных. http://hsqldb.org/ Новый экземпляр этого будет создаваться каждый раз, когда мы запускаем сервер. Для настройки базы данных все, что нам нужно сделать, это определить ее в весеннем конфиге trade-servlet.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
|
< bean id = "sessionFactory" <bean id = "sessionFactory" class = "org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" > < property name = "packagesToScan" value = "com.dbc.model" /> < property name = "hibernateProperties" > < props > < prop key = "hibernate.show_sql" >true</ prop > < prop key = "hibernate.format_sql" >true</ prop > < prop key = "hibernate.transaction.factory_class" > org.hibernate.transaction.JDBCTransactionFactory </ prop > < prop key = "hibernate.dialect" >org.hibernate.dialect.HSQLDialect</ prop > < prop key = "hibernate.connection.pool_size" >0</ prop > < prop key = "hibernate.connection.driver_class" >org.hsqldb.jdbcDriver</ prop > < prop key = "hibernate.connection.url" > jdbc:hsqldb:target/data/tradedatabase;shutdown=true </ prop > < prop key = "hibernate.connection.username" >sa</ prop > < prop key = "hibernate.connection.password" ></ prop > < prop key = "hibernate.connection.autocommit" >true</ prop > < prop key = "hibernate.jdbc.batch_size" >0</ prop > < prop key = "hibernate.hbm2ddl.auto" >update</ prop > </ props > </ property > </ bean > |
Фабрика сеансов определяет детали подключения к нашей базе данных. Наиболее важным свойством является
1
|
< prop key = "hibernate.hbm2ddl.auto" >update</ prop > |
Это свойство сообщает hibernate об обновлении базы данных при запуске приложения. Это эффективно создаст таблицу для торгового объекта из аннотаций на нашем торговом объекте. Когда вы запустите тесты, вы увидите, что следующий SQL выполняется при запуске.
1
2
3
4
5
6
|
11:30:31,899 DEBUG org.hibernate.tool.hbm2ddl.SchemaUpdate SchemaUpdate:203 - create table Trade ( id bigint not null, description varchar(255), reference varchar(255), primary key ( id )) |
Это новая база данных и готова к работе.
Создание Restful интерфейса.
Я просто собираюсь осветить основы здесь. Для некоторых замечательных примеров перейдите по этим ссылкам http://blog.springsource.com/2009/03/08/rest-in-spring-3-mvc/ http://www.stupidjavatricks.com/?p=54
Как создать Spring Controller
Контроллер Spring — ключ ко всему этому примеру. Именно контроллер принимает наши запросы и передает их в торговую службу для обработки. Это определяет спокойный интерфейс. Мы используем @PathVariable, чтобы упростить задачу.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
@RequestMapping (value = "/create/trade/{id}" ) public ModelAndView createTrade( @PathVariable Long id) { Trade trade = new Trade(id); service.createTrade(trade); ModelAndView mav = new ModelAndView( "tradeView" , BindingResult.MODEL_KEY_PREFIX + "trade" , trade); return mav; } @RequestMapping (value = "/find/trade/{id}" ) public ModelAndView findTradeById( @PathVariable Long id) { Trade trade = service.getTradeById(id); ModelAndView mav = new ModelAndView( "tradeView" , BindingResult.MODEL_KEY_PREFIX + "trade" , trade); return mav; } |
Это работает довольно просто, заполняя идентификатор @PathVariable значением из / find / trade / {id} Например, запрос / find / trade / 1 заполнит ссылку на «1», запрос / find / trade / 29 заполнит ссылку на «29» Более подробную информацию можно найти здесь: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-uri-templates
Как настроить веб-приложение
Конфигурация веб-приложения в web.xml очень проста. Сначала мы регистрируем Spring Servlet
1
2
3
4
|
trade org.springframework.web.servlet.DispatcherServlet 1 |
Далее мы определяем отображение на сервлет. Это отображение передаст все запросы нашему сервлету.
1
2
|
trade /* |
Как настроить Spring
Конфигурация Spring состоит из нескольких отдельных элементов. Первая строка просто сообщает Spring, где искать аннотации
1
|
|
BeanNameViewResolver берет имя
1
|
|
Этот пугающе выглядящий фрагмент XML выполняет работу по обеспечению того, чтобы объект Trade возвращался как XML. XStream возьмет объект и автоматически преобразует его в формат XML.
1
2
3
|
|
Класс Trade определяет для этого аннотацию XStream.
1
2
|
@XStreamAlias ( "trade" ) public class Trade { |
В нашем случае вы можете видеть из теста, что мы получаем следующее из / search / trade / 1
1
2
3
4
|
1 |
Как запустить и остановить Jetty Server
Я использую Jetty Plugin, чтобы запустить сервер и развернуть файл war, содержащий сервисы. http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin Сервер запускается со следующим фрагментом из pom.xml
1
2
3
4
5
6
7
|
< execution > < id >start-jetty</ id > < phase >pre-integration-test</ phase > < goals > < goal >run</ goal > </ goals > </ execution > |
Сервер остановлен с помощью следующего фрагмента из файла pom.xml
1
2
3
4
5
6
7
|
< execution > < id >stop-jetty</ id > < phase >post-integration-test</ phase > < goals > < goal >stop</ goal > </ goals > </ execution > |
Как запустить интеграционные тесты
Интеграционные тесты выполняются с использованием отказоустойчивых, как описано в оригинальной статье http://johndobie.blogspot.com/2011/06/seperating-maven-unit-integration-tests.html Мы используем новый Spring RestTemplate для упрощения вызова службы.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
@Test public void testGetTradeFromRestService() throws Exception { long id = 10L; createTrade(id); String tradeXml = new RestTemplate() .getForObject( String. class , id); System.out.println(tradeXml); Trade trade = getTradeFromXml(tradeXml); assertEquals(trade.getId(), id); } |
Ссылка: тестирование интеграции Maven и Spring Restful Services от нашего партнера JCG Джона Доби в блоге Agile Engineering Techniques .