Более 300 проблем, исправленных в 12 проектах, усложняют отслеживание событий, произошедших с момента последнего выпуска. Итак, вот более подробный отрывок из некоторых новых функций, которые мы готовили во время последней итерации.
Специальные выборочные графики JPA.
После выпуска релиза Dijkstra мы смогли ссылаться на граф именованных сущностей, объявленный на сущности, посредством @EntityGraph
аннотации в репозиториях, поддерживаемых JPA. В приведенном ниже примере это заставляет имя и фамилию загружаться с нетерпением, в то время как все остальные остаются загруженными лениво.
@Entity
@NamedEntityGraphs(
@NamedEntityGraph(name = "with-tags",
attributeNodes = { @NamedAttributeNode("tags") }))
class Product {
@ManyToMany
Set<Tag> tags;
// other properties omitted
}
interface ProductRepository extends Repository<Customer, Long> {
@EntityGraph("with-tags")
Product findOneById(Long id);
}
Выпуск Гослинга теперь продвигает нашу историю JPA 2.1 на один шаг вперед, расширяя ее до специальных определений графиков. При явном указании свойств с помощью @EntityGraph(attributePaths = …)
метода запроса вам не нужно NamedEntityGraph
добавлять аннотацию к вашей сущности.
@Entity
class Product {
@ManyToMany
Set<Tag> tags;
// other properties omitted
}
interface ProductRepository extends Repository<Customer, Long> {
@EntityGraph(attributePaths = {"tags"})
Product findOneById(Long id);
}
Веб-поддержка Querydsl
Веб-поддержка Spring Data уже позволяет вам объявлять параметры типа Pageable
в методах вашего контроллера. Недавно представленная интеграция с Querydsl расширяет возможности, позволяя вам получить готовый к использованию продукт, Predicate
полученный непосредственно из строки запроса HTTP. Эта функция автоматически включается, когда @EnableSpringDataWebSupport
настроен и Querydsl найден в пути к классам.
Если Predicate
используется без дальнейшей настройки, мы попытаемся разрешить корневой тип для Predicate
разрешения из возвращаемого типа метода, хотя в большинстве случаев может быть лучше явно объявить желаемую ссылку на тип через @QuerydslPredicate(root = …)
. Имея это на месте, атрибуты строки запроса привязываются к соответствующим свойствам типа, который создает, например,
QUser.user.firstname.eq("Dave").and(QUser.user.lastname.eq("Matthews"))
от ?firstname=Dave&lastname=Matthews
использования привязки, зависящей от типа свойства по умолчанию.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Controller
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
static class UserController {
private final UserRepository repository;
@RequestMapping(value = "/", method = RequestMethod.GET)
String index(Model model,
@QuerydslPredicate(root = User.class) Predicate predicate,
Pageable pageable) {
model.addAttribute("users", repository.findAll(predicate, pageable));
return "index";
}
}
}
Теперь не всегда имеет смысл использовать привязку по умолчанию (равно), а скорее выделенную привязку для свойства или для конкретного типа. Для достижения этого просто переопределите значения по умолчанию, предоставив объект, QuerydslBinderCustomizer
который может быть зарегистрирован через @QuerydslPredicate(bindings = …)
или просто внедрен в хранилище.
interface UserRepository extends CrudRepository<User, String>,
QueryDslPredicateExecutor<User>,
QuerydslBinderCustomizer<QUser> {
// Query methods go here
@Override
default public void customize(QuerydslBindings bindings, QUser user) {
bindings.bind(user.nationality).first(
(path, value) -> path.equalsIgnoreCase(value)); // 1
bindings.bind(String.class).first(
(StringPath path, String value) -> path.containsIgnoreCase(value)); // 2
bindings.excluding(user.password);
}
}
Как вы можете видеть, мы используем лямбды Java 8 вдоль ссылок на типобезопасные свойства стороннего Querydsl, чтобы определить привязку для выделенного свойства (1) или для всех свойств данного типа (2). Использование QuerydslBindings.excluding
позволяет удалить пути из запросов.
Найдите полный рабочий пример в репозитории примеров Spring Data и ознакомьтесь со справочной документацией для получения подробной информации.
Spring Data REST
Поддержка Querydsl
Поддержка Querydsl, представленная в Spring Data Commons (см.), Была интегрирована в Spring Data REST. Это означает, что вы можете фильтровать ресурсы вашей коллекции, добавляя простые параметры запроса свойств в URI запроса.
В примере Spring Data REST обнажая адреса магазинов Starbucks, обратите внимание , как StoreRepository в настоящее время реализует как QueryDslPredicateExecutor
и QuerydslBinderCustomizer<QStore>
так же , как описано выше.
Ресурс сбора для хранилищ, предоставляемых Spring Data REST, позволит вам затем отправлять такие запросы:
$ http :8080/api/stores?address.city=York
{
"_embedded": {
"stores": [
{
"_links": {
…
},
"address": {
"city": "New York",
"location": { "x": -73.938421, "y": 40.851 },
"street": "803 W 181st St",
"zip": "10033-4516"
},
"name": "Washington Hgts/181st St"
},
{
"_links": {
…
},
"address": {
"city": "New York",
"location": { "x": -73.939822, "y": 40.84135 },
"street": "4001 Broadway",
"zip": "10032-1508"
},
"name": "168th & Broadway"
},
…
]
},
"_links": {
…
},
"page": {
"number": 0,
"size": 20,
"totalElements": 209,
"totalPages": 11
}
}
Обратите внимание, как возвращаются только магазины, чей город оканчивается на «Йорк», как определено в реализации QuerydslBinderCustomizer
в StoresRepository
.
В настоящее время мы ищем варианты, чтобы более четко рекламировать этот механизм запросов, например, использовать переменные шаблона и даже предоставлять расширенные средства отображения для настройки имен параметров запроса, которые будут использоваться.
Пользовательский браузер HAL
Релиз Gosling Spring Data REST поставляется с дополнительным модулем, который оборачивает HAL-браузер Майка Келли и настраивает его с помощью нескольких настроек, позволяющих использовать метаданные API, которые мы предоставляем. Чтобы использовать браузер с вашим приложением, просто добавьте spring-data-rest-hal-browser
модуль в ваш проект, и ваш корень API будет обслуживать браузер для приема запросов text/html
. Стандартные ответы HAL, конечно, по-прежнему обслуживаются по умолчанию или если вы используете Accept
заголовок на основе JSON .
Хотя модуль Spring Data REST позволяет легко добавить браузер в ваше приложение, он также слегка настраивает браузер. Когда вы нажимаете кнопку, чтобы вызвать незапрошенный GET
запрос, браузер обычно открывает модальное диалоговое окно, которое ожидает некоторый необработанный ввод JSON. Хотя это, конечно, замечательно, если вы знаете, что делаете, это немного подвержено ошибкам и не очень удобно, так как вы должны знать о структуре данных, которую ожидает сервер.
Spring Data REST предоставляет документы схемы JSON для типов, предоставляемых системой, используя profile
отношение ссылок, что делает схему общедоступной для обнаружения без привязки логики обнаружения к самому Spring Data REST. Экземпляр браузера, который мы отправляем, ищет эти метаданные схемы и, если он может их найти, передает их редактору JSON, чтобы заменить диалог по умолчанию формой, полностью производной от схемы JSON.
Посмотрите, как форма позволяет добавлять позиции, поскольку схема представляет ее как массив. Поля цены и даты заказа помечены как доступные только для чтения, поле местоположения позволяет выбирать значения из перечисления с интернационализированными значениями.
Пример проекта можно найти на GitHub .
Интернационализация ссылок и перечислений
Как вы могли видеть на скриншотах выше, restbucks:orders
ссылка сопровождалась понятным для человека описанием. Описания извлекаются из необязательного пакета ресурсов rest-messages
с использованием _links.$rel.title
ключей для определения читаемого значения. В этом примере используется rest-messages.properties
запасной пакет ресурсов, но он также содержит rest-messages_de.properties
метки для возврата немецких меток для клиентов, отправляющих Accept-Language
набор заголовков de
.
Тот же пакет ресурсов можно использовать для интернационализации значений перечисления, чтобы их можно было использовать на клиенте в удобочитаемой форме. Чтобы не сломать существующие приложения, это должно быть явно активировано через RepositoryRestConfiguration.setEnableEnumTranslation(…)
. Подробности о переводе можно настроить на EnumTranslationConfiguration
.
Spring Data GemFire и Apache Geode
Поддержка Pivotal GemFire 8.1 и Apache Geode является наиболее заметным дополнением к Spring Data GemFire 1.7. Pivotal GemFire был представлен инкубатору Apache ранее в этом году, и команда Spring Data быстро отреагировала, чтобы включить поддержку в Spring Data GemFire.
Кроме того, было добавлено несколько других функций для упрощения разработки приложений GemFire и Apache Geode с использованием Spring. Например, разработчики могут теперь определять конкретные политики истечения срока действия объекта домена приложения, используя аннотации:
@TimeToLiveExpiration(
timeout = "@expirationSettings['spel.defined.timeout']" action="DESTROY")
@IdleTimeoutExpiration(
timeout = "1800" action="${property.placeholder.defined.action}")
class ApplicationDomainObject { … }
Аннотации годности на основе поддержки как SPEL и Spring PlaceHolder собственности значения. Чтобы включить политики истечения срока действия на основе аннотаций, вам нужно только настроить реализацию CustomExpiry Spring Data GemFire , AnnotationBasedExpiration , в регионах GemFire для одного или обоих типов TTL и TTI:
<gfe:partitioned-region id="Example" persistent="false" …>
<gfe:custom-entry-ttl>
<bean class="….gemfire.support.AnnotationBasedExpiration" factory-method="forTimeToLive"/>
</gfe:custom-entry-ttl>
<gfe:custom-entry-tti ref="ttiExpiration"/>
</gfe:partitioned-region>
<bean id="ttiExpiration" class="….gemfire.support.AnnotationBasedExpiration" factory-method="forIdleTimeout">
<constructor-arg ref="defaultExpirationAttributes"/>
</bean>
<bean id="defaultExpirationAttributes" class="….ExpirationAttributes">
<constructor-arg value="600"/>
<constructor-arg value="#{T(….ExpirationAction).DESTROY}"/>
</bean>
Смотрите справочное руководство, чтобы узнать больше . Далее была добавлена поддержка расширений OQL методом запросов к репозиторию с помощью аннотаций:
interface CustomerRepository implements CrudRepository<Cutomer, Long> {
@Trace
@Limit(25)
@Import("org.exmple.Customer")
@Hint("CustomerLastNameIdx")
List<Customer> findByLastNameOrderByLastNameAsc(String lastName);
}
@Trace
включает отладку отдельных операторов OQL. @Limit
ограничивает число результатов в наборе результатов запроса и @Import
позволяет приложениям различать типы объектов с одинаковыми именами. Например, ваше приложение может определять как org.example.app.core.Customer
и org.example.app.vendor.xyz.Customer
типы. См GemFire в документ для получения более подробной информации. @Hint
позволяет использовать подсказки OQL для определения индексов, применимых к запросу. Узнайте больше о расширениях OQL здесь .
Наконец, Spring Data GemFire предлагает поддержку GemFire Cache и моментальных снимков регионов, используя пространство имен Spring Data GemFire XML:
<gfe:partitioned-region id="Example" persistent="false" … />
<gfe-data:snapshot-service id="exampleRegionSnapshotService" region-ref="Example">
<gfe-data:snapshot-import location="/path/to/import/example.snapshot"/>
<gfe-data:snapshot-export locator="/path/to/export/example.snapshot"/>
</gfe-data:snapshot-service>
Вы можете узнать больше о том, как Spring Data GemFire поддерживает ZIP-файлы при импорте, об использовании Spring ApplicationEvents
для запуска импорта и экспорта моментальных снимков, а также о том, как правильно фильтровать данные, импортируемые и экспортируемые, здесь .
Spring Data KeyValue и хранилища на основе карт
Прошло довольно много времени с тех пор, как нас попросили предоставить очень простую Map
основанную реализацию для репозиториев Spring Data для различных — в основном для тестирования — целей. В конечном итоге запросы завершились активацией модуля KeyValue немного другим способом, чем он существовал ранее.
Spring Data KeyValue теперь состоит из базовой Map
реализации репозитория, которая будет использовать Spring Expression Language (SpEL) для запроса значений по умолчанию, обеспечивает сортировку, разбиение на страницы и интеграцию Querydsl на основе своего модуля сбора. Он также предоставляет специальные API-интерфейсы, позволяющие хранилищам ключей-значений использовать специфичные для магазина оптимизации при хранении, поиске и, что наиболее важно, при выполнении запросов, если это необходимо.
Механизм запросов по умолчанию, используемый репозиториями Spring Data KeyValue, основан на SpEL и позволяет определять и выполнять сложные запросы. Этот подход демонстрирует свою реальную мощность при запуске в COMPILED
режиме, поскольку он эффективно компилирует выражения фильтра, которые должны быть выполнены для значений. В качестве альтернативы вы также можете использовать выражения Querydsl для безопасных запросов.
@Configuration
@EnableMapRepositories("com.acme.repositories")
class AppConfig {}
@KeySpace("user")
class User {
String @Id id;
String firstname;
}
interface UserRepository extends CrudRepository<User, String> {
List<String> findByFirstnameStartingWith(String firstname);
}
В настоящее время у нас есть расширения этого API для Ehcache, Hazelcast и Aerospike, и мы с нетерпением ждем возможности оценить возможности интеграции Redis и, возможно, перенести некоторые из API Gemfire для их использования.
Что дальше?
Следующим шагом будет SpringOne2GX в Вашингтоне, округ Колумбия — мы будем рады видеть вас там — лучшее место, чтобы связаться с командой, узнать о новых возможностях и просто приятно провести время. Тем временем мы уже готовим следующий сервисный релиз для поезда выпуска Фаулера и начали работу над новыми функциями для поезда выпуска Хоппера (Sshh … Мы дадим краткую характеристику Hopper в выступлении «Что нового в Spring Data?» На SpringOne ).
Релиз написан Кристофом Штроблом.