Что такое весна-дата-отдых?
spring-data-rest , недавнее дополнение к проекту spring-data , является платформой, которая помогает вам представить ваши сущности непосредственно как конечные точки веб-сервиса RESTful. В отличие от rails, grails или roo, он не генерирует никакого кода для достижения этой цели. Spring data-rest поддерживает проверку JPA, MongoDB, JSR-303, HAL и многие другие. Он действительно инновационный и позволяет настроить веб-сервис RESTful за считанные минуты. В этом примере я дам вам краткий обзор того, на что способен spring-data-rest.
Начальная конфигурация
Я собираюсь использовать новую веб-конфигурацию Java Servlet 3 вместо древнего web.xml. Здесь нет ничего особенного.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[]{AppConfiguration. class }; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{WebConfiguration. class }; } @Override protected String[] getServletMappings() { return new String[]{ "/" }; } } |
WebAppInitializer.java на github
Я инициализирую hibernate как уровень абстракции базы данных в классе AppConfiguration . Я использую встроенную базу данных ( hsql ), так как хочу, чтобы эта витрина была простой, глупой. Тем не менее, здесь ничего особенного.
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
|
@Configuration @EnableJpaRepositories @EnableTransactionManagement public class AppConfiguration { @Bean public DataSource dataSource() { EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); return builder.setType(EmbeddedDatabaseType.HSQL).build(); } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setDatabase(Database.HSQL); vendorAdapter.setGenerateDdl( true ); LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); factory.setJpaVendorAdapter(vendorAdapter); factory.setPackagesToScan(getClass().getPackage().getName()); factory.setDataSource(dataSource()); return factory; } @Bean public PlatformTransactionManager transactionManager() { return new JpaTransactionManager(); } } |
AppConfiguration.java на github
Теперь к настройке сервлета приложения: WebConfiguration
1
2
3
|
@Configuration public class WebConfiguration extends RepositoryRestMvcConfiguration { } |
WebConfiguration.java на github
О, ну это немного коротко, не так ли? Для полной настройки не требуется ни одной строки кода. Это действительно хорошее применение соглашения о конфигурации парадигмы. Теперь мы можем начать создавать репозитории spring-data-jpa, так как они будут автоматически представлены как ресурсы RESTful. И мы все еще можем добавить пользовательскую конфигурацию в класс WebConfiguration, если это необходимо.
Инициализация была действительно короткой и легкой. Нам не нужно было ничего особенного кодировать. Единственное, что мы сделали, — это установили соединение с базой данных и режим гибернации, что, очевидно, неизбежно. Теперь, когда мы настроили наш «REST Servlet» и постоянство, давайте перейдем к самому приложению, начиная с модели.
Модель
Я сделаю это очень просто, создав только два связанных объекта.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
@Entity public class Book { @Id private String isbn; private String title; private String language; @ManyToMany private List<Author> authors; } |
01
02
03
04
05
06
07
08
09
10
11
12
13
|
@Entity public class Author { @Id @GeneratedValue (strategy = GenerationType.SEQUENCE) private Integer id; private String name; @ManyToMany (mappedBy = "authors" ) private List<Book> books; } |
Чтобы наконец сделать сущности постоянными и выставленными как веб-сервис RESTful, нам нужны репозитории Spring-Data. Хранилище — это в основном DAO . Он предлагает функциональность CRUD для наших организаций. Spring-data отнимает большую часть ваших усилий по программированию, создавая такие репозитории. Нам просто нужно определить пустой интерфейс, Spring-Data делает все остальное из коробки. Тем не менее, он легко настраивается благодаря своему дизайну по соглашению над конфигурацией!
Актуальные репозитории
1
2
3
|
@RestResource (path = "books" , rel = "books" ) public interface BookRepository extends PagingAndSortingRepository<Book, Long> { } |
1
2
3
|
@RestResource (path = "authors" , rel = "authors" ) public interface AuthorRepository extends PagingAndSortingRepository<Author, Integer> { } |
AuthorRepository.java на github
Опять же, код почти не нужен. Даже аннотация @RestResource может быть опущена . Но если бы я это сделал, путь и rel были бы названы в честь сущности, которую я не хочу. Ресурс REST, содержащий несколько дочерних элементов, должен называться множественным.
Доступ к результату
Наш веб-сервис RESTful готов к развертыванию. После запуска он перечисляет все доступные ресурсы в корне, поэтому вы можете перемещаться оттуда.
ПОЛУЧИТЕ http: // localhost: 8080 /
01
02
03
04
05
06
07
08
09
10
|
{ "links" : [ { "rel" : "books" , }, { "rel" : "authors" , } ], "content" : [ ] } |
Отлично! Теперь давайте создадим автора и книгу.
POST http: // localhost: 8080 / авторы
1
|
{ "name" : "Uncle Bob" } |
отклик
1
2
|
201 Created Location: http: //localhost:8080/authors/1 |
PUT http: // localhost: 8080 / books / 0132350882
1
2
3
4
5
6
7
8
9
|
{ "title" : "Clean Code" , "authors" : [ { "rel" : "authors" , } ] } |
отклик
1
|
201 Created |
Заметили, как я использовал PUT для создания книги? Это потому, что его идентификатор является фактическим isbn. Я должен сказать серверу, какой isbn использовать, так как он не может догадаться. Я использовал POST для автора, поскольку его идентификатор — это просто инкрементное число, которое генерируется автоматически. Кроме того, я использовал ссылку, чтобы соединить и книгу ( / books / 0132350882 ) и автора ( / авторы / 1 ). Это в основном то, что гипермедиа все о: ссылки используются для навигации и отношений между сущностями.
Теперь давайте посмотрим, была ли книга создана соответствующим образом.
ПОЛУЧИТЕ http: // localhost: 8080 / books
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
{ "links" : [ ], "content" : [ { "links" : [ { "rel" : "books.Book.authors" , }, { "rel" : "self" , } ], "title" : "Clean Code" } ], "page" : { "size" : 20 , "totalElements" : 1 , "totalPages" : 1 , "number" : 1 } } |
Отлично!
Вот тест интеграции, следуя этим шагам автоматически. Это также доступно в примере на github.
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
|
public class BookApiIT { private final RestTemplate restTemplate = new RestTemplate(); @Test public void testCreateBookWithAuthor() throws Exception { final URI authorUri = restTemplate.postForLocation(authorsUrl, sampleAuthor()); // create Author final URI bookUri = new URI(booksUrl + "/" + sampleBookIsbn); restTemplate.put(bookUri, sampleBook(authorUri.toString())); // create Book linked to Author Resource<Book> book = getBook(bookUri); assertNotNull(book); final URI authorsOfBookUri = new URI(book.getLink( "books.Book.authors" ).getHref()); Resource<List<Resource<Author>>> authors = getAuthors(authorsOfBookUri); assertNotNull(authors.getContent()); assertFalse(authors.getContent().isEmpty()); // check if /books/0132350882/authors contains an author } private String sampleAuthor() { return "{\"name\":\"Robert C. Martin\"}" ; } private final String sampleBookIsbn = "0132350882" ; private String sampleBook(String authorUrl) { return "{\"title\":\"Clean Code\",\"authors\":[{\"rel\":\"authors\",\"href\":\"" + authorUrl + "\"}]}" ; } private Resource<Book> getBook(URI uri) { return restTemplate.exchange(uri, HttpMethod.GET, null , new ParameterizedTypeReference<Resource<Book>>() { }).getBody(); } private Resource<List<Resource<Author>>> getAuthors(URI uri) { return restTemplate.exchange(uri, HttpMethod.GET, null , new ParameterizedTypeReference<Resource<List<Resource<Author>>>>() { }).getBody(); } } |
Вывод
Мы создали полный веб-сервис RESTful без особых усилий по написанию кода. Мы только что определили наши сущности и связь с базой данных. spring-data-rest заявил, что все остальное просто шаблон, и я согласен.
Чтобы использовать веб-сервисы вручную, рассмотрите остальные оболочки . Это командная оболочка, делающая навигацию в вашем веб-сервисе максимально простой и увлекательной. Вот скриншот:
Полный пример доступен на моем github
https://github.com/gregorriegler/babdev-spring/tree/master/spring-data-rest
https://github.com/gregorriegler/babdev-spring