Введение
Уже прошло несколько лет с тех пор, как появился JPA. Работа с EntityManager увлекательна, но разработчики пишут красивый API, а подробности работы с базой данных скрывают. При этом частая проблема - дублирование имплементации, когда из одного DAO в другой у нас плавно перекочёвывает один и тот же код, в лучшем случае этот код переносится в абстрактный базовый DAO. Spring Data коренным образом решает проблему - при его использовании остаётся только API на уровне интерфейсов, вся имплементация создаётся автоматически с использованием AOP.
История Spring Data
Несмотря на то, что проект только недавно достиг версии 1.0, у него достаточно богатая история - раньше он развивался в рамках проекта
Hades.
Объявление DAO-интерфейса
Итак, для начала нам необходимо объявить DAO-интерфейс, в котором мы будем объявлять методы для работы с сущностью.
public interface UserRepository extends CrudRepository<User, Long> {
}
Данного кода достаточно для обычного DAO с
CRUD-методами.
- save - сохраняет или обновляет переданную сущность.
- findOne - ищет сущность по первичному ключу.
- findAll - возвращает коллекцию всех сущностей
- count - возвращает количество сущностей
- delete - удаляет сущность
- exists - проверяет, существует ли сущность с данным первичным ключом
Полный список методов, объявленный в CrudRepository можно посмотреть в
javadoc.
В случае, если нам нужны не все методы, то есть возможность произвести наследование от интерфейса
Repository и перенести в наследника только те методы из интерфейса CrudRepository, которые нужны.
Поддержка сортировки и постраничного просмотра
Очень часто требующаяся функциональность - это возможность возвращать только часть сущностей из БД, например, для реализации постраничного просмотра в пользовательском интерфейсе. Spring Data и тут хорош и предоставляет нам возможность добавить такую функциональность в наш DAO. Для этого достаточно добавить объявление следующего метода в наш DAO-интерфейс:
Page<User> findAll(Pageable pageable);
Интерфейс
Pageable инкапсулирует в себе сведения о номере запрашиваемой страницы, размере страницы, а также требуемой сортировке.
Ищем данные
Как правило, на обычных CRUD-ах DAO не заканчиваются и часто требуются дополнительные методы, которые возвращают только те сущности, которые удовлетворяют заданным условиям. На мой взгляд, Spring Data сильно упрощает жизнь в данной области.
Например, нам нужен методы для поиска пользователя по логину и по его e-mail адресу:
User findByLogin(String login);
User findByEmail(String email);
Все просто.
В случае, если нужны более сложные условия для поиска, то и это тоже реализовано.
Spring Data поддерживает следующие операторы:
- Between
- IsNotNull
- NotNull
- IsNull
- Null
- LessThan
- LessThanEqual
- GreaterThan
- GreaterThanEqual
- NotLike
- Like
- NotIn
- In
- Near
- Within
- Regex
- Exists
- IsTrue
- True
- IsFalse
- False
- Not
Такой внушительный список открывает простор для фантазии, так что можно составить сколь угодно сложный запрос.
Если необходимо, чтобы в результатах поиска было несколько сущностей, то необходимо называть метод find
AllByBlahBlah
Поддержка Spring MVC
Это часть основана на официальной документации.
Представьте, что вы разрабатываете веб-приложение с использованием
Spring MVC. Тогда вам необходимо будет загружать сущность из базы данных используя параметры HTTP-запроса. Это может выглядеть следующим образом:
@Controller
@RequestMapping("/users")
public class UserController {
private final UserRepository userRepository;
public UserController(UserRepository userRepository) {
userRepository = userRepository;
}
@RequestMapping("/{id}")
public String showUserForm(@PathVariable("id") Long id, Model model) {
// Do null check for id
User user = userRepository.findOne(id);
// Do null check for user
// Populate model
return "user";
}
}
Во-первых, вы объявляете зависимость на DAO, а во-вторых всегда вызываете метод
findOne() для загрузки сущности. К счастью, Spring позволяет нам преобразовывать строковые значения из HTTP-запросов в любой нужный тип используя либо
PropertyEditor, либо
ConversionService.
Если вы используете Spring версии 3.0 и выше, то вам необходимо добавить следующую конфигурацию:
<mvc:annotation-driven conversion-service="conversionService" />
<bean id="conversionService" class="….context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="org.springframework.data.repository.support.DomainClassConverter">
<constructor-arg ref="conversionService" />
</bean>
</list>
</property>
</bean>
Если же вы используете Spring более старой версии, то вам необходима вот такая конфигурация:
<bean class="….web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="….web.bind.support.ConfigurableWebBindingInitializer">
<property name="propertyEditorRegistrars">
<bean class="org.springframework.data.repository.support.DomainClassPropertyEditorRegistrar" />
</property>
</bean>
</property>
</bean>
После данных изменений в конфигурации можно переписать контроллер следующим образом:
@Controller
@RequestMapping("/users")
public class UserController {
@RequestMapping("/{id}")
public String showUserForm(@PathVariable("id") User user, Model model) {
// Do null check for user
// Populate model
return "userForm";
}
}
Обратите внимание на то, как упростился код и как мы красиво избавились от его дублирования.
Документация
На данный момент документации по проекту не так уж и много, но, тем не менее, она есть:
Заключение
Spring Data значительно упрощает жизнь при использовании JPA. Рекомендуется к использованию в своих проектах.
2. Для монги есть отдельный проект - Spring Data MongoDB, который поддерживает вышеперечисленный операторы.
В документации всё описано - http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/#mongo.query