вступление
Сегодня я расскажу о более конкретных вопросах. Никаких шаблонов проектирования или алгоритмов на этот раз :-). Мы не всегда разрабатываем программные компоненты с нуля. Часто нам приходится пытаться заставить существующие программные компоненты работать вместе.
Spring Boot является одним из лучших бесплатных программ в мире Java. Это решило множество проблем с настройкой Spring. Он очень гибкий и предлагает отличную функциональность.
Spring Data является частью коллекции проектов Spring. Предлагает расширенные инструменты для работы с базами данных. Одним из наиболее полезных является автоматический репозиторий. Класс может реализовать JpaRepository, и большинство методов для работы с данными будут созданы автоматически.
Thymeleaf — это шаблонизатор HTML. Он может использовать некоторые функции Spring Boot, такие как методы вызова bean-компонентов Spring в шаблоне и многое другое. Официальная документация имеет отличные учебники.
Я использовал spring-boot-starter-parent версии 2.0.1.RELEASE — 2.0.4.RELEASE. Другие зависимости были предоставлены Spring Boot.
описание проблемы
Основная идея любого приложения, работающего с Spring Boot, Spring Data и Thymeleaf, заключается в редактировании данных в базе данных. Spring-boot-starter-data-jpa включает Hibernate, который можно использовать для манипулирования данными в базе данных. Thymeleaf можно использовать для отображения данных пользователю. Spring Boot соединяет все это вместе.
Очень простой сценарий включает в себя один объект с отношениями «один ко многим» с другим объектом. Пользователь хочет иметь возможность создать новую сущность и выбрать другую сущность в HTML
выберите поле.
Вот где появляется первый номер. Со стандартной структурой Thymeleaf базовый компонент не может быть собран. Объект, который был выбран в поле выбора, имеет следующую конструкцию:
01
02
03
04
05
06
07
08
09
10
|
< form action = "#" th:action="@{/<some Action>}" th:object="${beanObj}" method="post"> .... < other fields> < select th:field = "*{room}" class = "textinput" > < option th:each = "currRoom : ${allRooms}" th:value = "${currRoom}" th:text = "${currRoom.name}" >no name</ option > </ select > </ form > |
не создан Thymeleaf. Я не нашел упоминания об этом в официальной документации.
Решение
После некоторой отладки я нашел основную причину. Оказалось, что Thymeleaf передает все поля как параметры для запроса POST. Он использует метод toString для преобразования объекта в String и добавления в качестве параметра в запрос POST. Он отправляет такой параметр:
1
|
room: Room+[ id =273,+name=room111] |
В методе контроллера это значение должно быть преобразовано обратно в форму объекта. Spring Boot использует конвертеры для этого.
Решение состоит в том, чтобы зарегистрировать соответствующие конвертеры в ConversionService. И используйте эти конвертеры в методе toString сущностей, чтобы убедиться, что один и тот же метод используется для преобразования в форму String и обратно.
Следующие проблемы
Звучит смешно, не правда ли? Решение найдено, но больше проблем? На самом деле описанное решение хорошо работает без Spring Data. В Spring Data преобразование снова не выполняется. И Spring Boot хочет, чтобы вы создали бин entityManagerFactory, даже если этот бин не был нужен без Spring Data.
Следующие решения
Проблема с компонентом entityManagerFactory может быть решена путем интенсивного поиска в Интернете. Вот решение, которое я выбрал:
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
|
@Primary @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource ds) { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(ds); em.setPackagesToScan( "<some packages>" ); JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); em.setJpaProperties(additionalProperties()); return em; } @Bean public SessionFactory sessionFactory( @Qualifier ( "entityManagerFactory" ) EntityManagerFactory emf) { return emf.unwrap(SessionFactory. class ); } private Properties additionalProperties() { Properties properties = new Properties(); properties.setProperty( "hibernate.dialect" , "org.hibernate.dialect.PostgreSQLDialect" ); properties.setProperty( "hibernate.default_schema" , "public" ); properties.setProperty( "hibernate.show_sql" , "true" ); // Validation will fail because the tables use bigint as the ID but it is mapped to the Integer type by Hibernate // Validation expects a 8-bit number as the mapping to bigint. properties.setProperty( "hibernate.hbm2ddl.auto" , "none" ); return properties; } |
Вторая проблема оказалась более сложной и потребовала много отладки. В конце концов я обнаружил, что spring-data каким-то образом меняет сервис конвертации, который использует Spring Boot. Вместо используемого по умолчанию конверсионного сервиса Spring Data используется mvcConversionService. Форматеры / преобразователи должны быть добавлены в ваш класс WebMvcConfigurer (класс, который реализует WebMvcConfigurer). Метод addFormatters:
1
2
3
4
5
|
@Override public void addFormatters(FormatterRegistry registry) { registry.addConverter( new <SomeConverter>); ... |
Теперь, когда все проблемы решены, Spring Data может работать с Thymeleaf.
Удачного кодирования и старательной отладки!
Опубликовано на Java Code Geeks с разрешения Вадима Коркина, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Spring Data с Thymeleaf
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |