Что такое весна-дата-отдых?
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@EnableTransactionManagementpublic 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
|
@Configurationpublic 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
|
@Entitypublic 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
|
@Entitypublic 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 CreatedLocation: 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