Статьи

Весенние данные с Thymeleaf

вступление

Сегодня я расскажу о более конкретных вопросах. Никаких шаблонов проектирования или алгоритмов на этот раз :-). Мы не всегда разрабатываем программные компоненты с нуля. Часто нам приходится пытаться заставить существующие программные компоненты работать вместе.

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

Вот где появляется первый номер. Со стандартной структурой 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, являются их собственными.