diff --git a/booking-mvc/pom.xml b/booking-mvc/pom.xml
index 9c92a65..57cb130 100644
--- a/booking-mvc/pom.xml
+++ b/booking-mvc/pom.xml
@@ -41,88 +41,56 @@
org.springframework.securityspring-security-web
- ${spring-security.version}org.springframework.securityspring-security-taglibs
- ${spring-security.version}org.springframework.securityspring-security-config
- ${spring-security.version}
- javax.servlet
- javax.servlet-api
+ jakarta.servlet
+ jakarta.servlet-api${servlet.version}provided
- javax.servlet.jsp
- jsp-api
- 2.1
+ jakarta.servlet.jsp
+ jakarta.servlet.jsp-api
+ ${jsp-api.version}provided
- javax.servlet
- jstl
- 1.2
+ jakarta.servlet.jsp.jstl
+ jakarta.servlet.jsp.jstl-api
+ ${jstl-api}org.thymeleafthymeleaf
- 2.1.5.RELEASE
+ 3.1.0.M1org.thymeleaf
- thymeleaf-spring4
- 2.1.5.RELEASE
+ thymeleaf-spring6
+ 3.1.0.M1org.thymeleaf.extras
- thymeleaf-extras-tiles2-spring4
- 2.1.1.RELEASE
-
-
- org.thymeleaf.extras
- thymeleaf-extras-springsecurity4
- 2.1.2.RELEASE
+ thymeleaf-extras-springsecurity6
+ 3.1.0.M1
+
-
- org.apache.tiles
- tiles-core
- ${tiles.version}
-
-
- org.apache.tiles
- tiles-api
- ${tiles.version}
-
-
- org.apache.tiles
- tiles-template
- ${tiles.version}
-
-
- org.apache.tiles
- tiles-servlet
- ${tiles.version}
-
-
- org.apache.tiles
- tiles-jsp
- ${tiles.version}
-
+ -->
org.hsqldb
@@ -130,14 +98,25 @@
${hsqldb.version}runtime
+
+ org.hibernate
+ hibernate-core-jakarta
+ ${hibernate.version}
+ org.hibernatehibernate-entitymanager${hibernate.version}
+
+
+ org.hibernate
+ hibernate-core
+
+
- org.hibernate
+ org.hibernate.validatorhibernate-validator${hibernate-validator.version}
@@ -215,16 +194,16 @@
org.apache.maven.pluginsmaven-compiler-plugin
- 3.7.0
+ 3.10.1
- 1.8
- 1.8
+ 17
+ 17org.apache.maven.pluginsmaven-surefire-plugin
- 2.20.1
+ ${maven-surefire-plugin.version}junit:junit
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/Booking.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/Booking.java
index dba0cf3..b13fc5d 100755
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/Booking.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/Booking.java
@@ -7,17 +7,17 @@
import java.util.Date;
import java.util.Set;
-import javax.persistence.Basic;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.ManyToOne;
-import javax.persistence.Temporal;
-import javax.persistence.TemporalType;
-import javax.persistence.Transient;
-import javax.validation.constraints.Future;
-import javax.validation.constraints.NotNull;
+import jakarta.persistence.Basic;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Temporal;
+import jakarta.persistence.TemporalType;
+import jakarta.persistence.Transient;
+import jakarta.validation.constraints.Future;
+import jakarta.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/BookingDateRange.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/BookingDateRange.java
index a5cad18..f9d4708 100644
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/BookingDateRange.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/BookingDateRange.java
@@ -5,8 +5,8 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import javax.validation.Constraint;
-import javax.validation.Payload;
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
@Constraint(validatedBy = BookingDateRangeValidator.class)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/BookingDateRangeValidator.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/BookingDateRangeValidator.java
index 716a40b..ee7c133 100644
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/BookingDateRangeValidator.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/BookingDateRangeValidator.java
@@ -1,7 +1,7 @@
package org.springframework.webflow.samples.booking;
-import javax.validation.ConstraintValidator;
-import javax.validation.ConstraintValidatorContext;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
public class BookingDateRangeValidator implements ConstraintValidator {
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/BookingFlowHandler.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/BookingFlowHandler.java
index ae531e7..516e855 100644
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/BookingFlowHandler.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/BookingFlowHandler.java
@@ -1,7 +1,7 @@
package org.springframework.webflow.samples.booking;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.springframework.webflow.core.FlowException;
import org.springframework.webflow.execution.FlowExecutionOutcome;
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/Hotel.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/Hotel.java
index 3bdad77..57ecd29 100755
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/Hotel.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/Hotel.java
@@ -3,10 +3,10 @@
import java.io.Serializable;
import java.math.BigDecimal;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Id;
/**
* A hotel where users may book stays.
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/HotelsController.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/HotelsController.java
index 5a11404..3e5da3c 100644
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/HotelsController.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/HotelsController.java
@@ -21,7 +21,7 @@ public HotelsController(BookingService bookingService) {
}
@GetMapping("/hotels/search")
- public void search(SearchCriteria searchCriteria, Principal currentUser, Model model) {
+ public void search(@SuppressWarnings("unused") SearchCriteria searchCriteria, Principal currentUser, Model model) {
if (currentUser != null) {
List booking = bookingService.findBookings(currentUser.getName());
model.addAttribute(booking);
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/JpaBookingService.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/JpaBookingService.java
index c05c76c..851026c 100755
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/JpaBookingService.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/JpaBookingService.java
@@ -2,8 +2,8 @@
import java.util.List;
-import javax.persistence.EntityManager;
-import javax.persistence.PersistenceContext;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/User.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/User.java
index f0f6bae..f05e00a 100755
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/User.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/User.java
@@ -2,9 +2,9 @@
import java.io.Serializable;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
/**
* A user who can book hotels.
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/DataAccessConfig.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/DataAccessConfig.java
index 53166aa..22bd9b1 100644
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/DataAccessConfig.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/DataAccessConfig.java
@@ -2,7 +2,7 @@
import java.util.Collections;
-import javax.persistence.EntityManagerFactory;
+import jakarta.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/DispatcherServletInitializer.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/DispatcherServletInitializer.java
index c86c1e0..a2749a2 100644
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/DispatcherServletInitializer.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/DispatcherServletInitializer.java
@@ -1,6 +1,6 @@
package org.springframework.webflow.samples.booking.config;
-import javax.servlet.Filter;
+import jakarta.servlet.Filter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/SecurityConfig.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/SecurityConfig.java
index c31f82b..6d496b0 100644
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/SecurityConfig.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/SecurityConfig.java
@@ -5,6 +5,7 @@
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
@@ -20,7 +21,7 @@ protected void configure(HttpSecurity http) throws Exception {
.failureUrl("/login?login_error=1")
.and()
.logout()
- .logoutUrl("/logout")
+ .logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
.logoutSuccessUrl("/logoutSuccess");
}
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/SecurityWebApplicationInitializer.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/SecurityWebApplicationInitializer.java
index df49deb..f20d751 100644
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/SecurityWebApplicationInitializer.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/SecurityWebApplicationInitializer.java
@@ -7,4 +7,5 @@
* the chain of Spring Security filters.
*/
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
+
}
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/WebFlowConfig.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/WebFlowConfig.java
index 4582cb2..31a979f 100644
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/WebFlowConfig.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/WebFlowConfig.java
@@ -45,7 +45,7 @@ public FlowBuilderServices flowBuilderServices() {
@Bean
public MvcViewFactoryCreator mvcViewFactoryCreator() {
MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
- factoryCreator.setViewResolvers(Collections.singletonList(this.webMvcConfig.viewResolver()));
+ factoryCreator.setViewResolvers(Collections.singletonList(this.webMvcConfig.thymeleafViewResolver()));
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
diff --git a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/WebMvcConfig.java b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/WebMvcConfig.java
index e5a3138..4851e13 100644
--- a/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/WebMvcConfig.java
+++ b/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/WebMvcConfig.java
@@ -1,28 +1,45 @@
package org.springframework.webflow.samples.booking.config;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import jakarta.servlet.ServletContext;
+import org.thymeleaf.dialect.IDialect;
+import org.thymeleaf.extras.springsecurity6.dialect.SpringSecurityDialect;
+import org.thymeleaf.spring6.SpringTemplateEngine;
+import org.thymeleaf.spring6.view.AjaxThymeleafViewResolver;
+import org.thymeleaf.spring6.view.FlowAjaxThymeleafView;
+import org.thymeleaf.templateresolver.WebApplicationTemplateResolver;
+import org.thymeleaf.web.IWebApplication;
+import org.thymeleaf.web.servlet.JakartaServletWebApplication;
+
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.web.context.ServletContextAware;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
-import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
import org.springframework.webflow.mvc.servlet.FlowHandlerAdapter;
import org.springframework.webflow.mvc.servlet.FlowHandlerMapping;
-import org.springframework.webflow.mvc.view.AjaxUrlBasedViewResolver;
-import org.springframework.webflow.mvc.view.FlowAjaxTiles3View;
import org.springframework.webflow.samples.booking.BookingFlowHandler;
@EnableWebMvc
@Configuration
-public class WebMvcConfig implements WebMvcConfigurer {
+public class WebMvcConfig implements WebMvcConfigurer, ServletContextAware {
@Autowired
private WebFlowConfig webFlowConfig;
+ private ServletContext servletContext;
+
+ @Override
+ public void setServletContext(ServletContext servletContext) {
+ this.servletContext = servletContext;
+ }
+
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/", "classpath:/META-INF/web-resources/");
@@ -62,17 +79,33 @@ public BookingFlowHandler BookingFlowHandler() {
}
@Bean
- public AjaxUrlBasedViewResolver viewResolver() {
- AjaxUrlBasedViewResolver resolver = new AjaxUrlBasedViewResolver();
- resolver.setViewClass(FlowAjaxTiles3View.class);
- return resolver;
+ public AjaxThymeleafViewResolver thymeleafViewResolver() {
+ AjaxThymeleafViewResolver viewResolver = new AjaxThymeleafViewResolver();
+ viewResolver.setViewClass(FlowAjaxThymeleafView.class);
+ viewResolver.setTemplateEngine(templateEngine());
+ return viewResolver;
}
@Bean
- public TilesConfigurer tilesConfigurer() {
- TilesConfigurer configurer = new TilesConfigurer();
- configurer.setDefinitions("/WEB-INF/**/views.xml");
- return configurer;
+ public SpringTemplateEngine templateEngine(){
+
+ Set dialects = new LinkedHashSet<>();
+ dialects.add(new SpringSecurityDialect());
+
+ SpringTemplateEngine templateEngine = new SpringTemplateEngine();
+ templateEngine.setTemplateResolver(templateResolver());
+ templateEngine.setAdditionalDialects(dialects);
+ return templateEngine;
+ }
+
+ @Bean
+ public WebApplicationTemplateResolver templateResolver() {
+ IWebApplication application = JakartaServletWebApplication.buildApplication(this.servletContext);
+ WebApplicationTemplateResolver resolver = new WebApplicationTemplateResolver(application);
+ resolver.setPrefix("/WEB-INF/");
+ resolver.setSuffix(".html");
+ resolver.setTemplateMode("HTML5");
+ return resolver;
}
}
diff --git a/booking-mvc/src/main/java/org/thymeleaf/spring6/view/AjaxEnabledView.java b/booking-mvc/src/main/java/org/thymeleaf/spring6/view/AjaxEnabledView.java
new file mode 100644
index 0000000..0ca8b50
--- /dev/null
+++ b/booking-mvc/src/main/java/org/thymeleaf/spring6/view/AjaxEnabledView.java
@@ -0,0 +1,82 @@
+/*
+ * =============================================================================
+ *
+ * Copyright (c) 2011-2018, The THYMELEAF team (http://www.thymeleaf.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * =============================================================================
+ */
+package org.thymeleaf.spring6.view;
+
+import org.springframework.web.servlet.View;
+import org.springframework.webflow.context.servlet.AjaxHandler;
+
+
+// Copied from thymeleaf-spring5.
+// Temporarily here until available in thymeleaf-spring6.
+
+
+/**
+ *
+ * Interface defining getter and setter methods for an
+ * {@code ajaxHandler} property in Views, so that they can
+ * be used in Spring AJAX environments.
+ *
+ * Return the AJAX handler (from Spring Javascript) used
+ * to determine whether a request is an AJAX request or not.
+ *
+ *
+ * Views implementing this interface should be used with an instance of
+ * {@link AjaxThymeleafViewResolver} or any of its subclasses,
+ * so that {@link #setAjaxHandler(AjaxHandler)} can be called by
+ * the resolver when resolving the view, setting the default
+ * AJAX handler being used.
+ *
+ *
+ * @return the AJAX handler.
+ */
+ public AjaxHandler getAjaxHandler();
+
+
+ /**
+ *
+ * Sets the AJAX handler (from Spring Javascript) used
+ * to determine whether a request is an AJAX request or not.
+ *
+ *
+ * Views implementing this interface should be used with an instance of
+ * {@link AjaxThymeleafViewResolver} or any of its subclasses,
+ * so that this method can be called by
+ * the resolver when resolving the view, setting the default
+ * AJAX handler being used.
+ *
+ *
+ * @param ajaxHandler the AJAX handler.
+ */
+ public void setAjaxHandler(final AjaxHandler ajaxHandler);
+
+
+}
\ No newline at end of file
diff --git a/booking-mvc/src/main/java/org/thymeleaf/spring6/view/AjaxThymeleafView.java b/booking-mvc/src/main/java/org/thymeleaf/spring6/view/AjaxThymeleafView.java
new file mode 100644
index 0000000..2016db2
--- /dev/null
+++ b/booking-mvc/src/main/java/org/thymeleaf/spring6/view/AjaxThymeleafView.java
@@ -0,0 +1,144 @@
+/*
+ * =============================================================================
+ *
+ * Copyright (c) 2011-2018, The THYMELEAF team (http://www.thymeleaf.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * =============================================================================
+ */
+package org.thymeleaf.spring6.view;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.StringUtils;
+import org.springframework.webflow.context.servlet.AjaxHandler;
+import org.thymeleaf.exceptions.ConfigurationException;
+
+
+// Copied from thymeleaf-spring5.
+// Temporarily here until available in thymeleaf-spring6.
+
+
+/**
+ *
+ * Subclass of {@link ThymeleafView} adding compatibility with AJAX events in
+ * Spring JavaScript (part of Spring WebFlow). This allows this View implementation
+ * to be able to return only fragments of the page.
+ *
+ *
+ * These rendering of fragments is used, for example, in Spring WebFlow's <render>
+ * instructions (though not only).
+ *
+ *
+ * This view searches for a comma-separated list of markup selectors in a request
+ * parameter called {@code fragments}.
+ *
+ *
+ * @author Daniel Fernández
+ *
+ * @since 3.0.3
+ *
+ */
+public class AjaxThymeleafView extends ThymeleafView implements AjaxEnabledView {
+
+ private static final Logger vlogger = LoggerFactory.getLogger(AjaxThymeleafView.class);
+
+ private static final String FRAGMENTS_PARAM = "fragments";
+
+
+ private AjaxHandler ajaxHandler = null;
+
+
+
+ public AjaxThymeleafView() {
+ super();
+ }
+
+
+
+ public AjaxHandler getAjaxHandler() {
+ return this.ajaxHandler;
+ }
+
+
+ public void setAjaxHandler(final AjaxHandler ajaxHandler) {
+ this.ajaxHandler = ajaxHandler;
+ }
+
+
+
+
+ @Override
+ public void render(final Map model, final HttpServletRequest request, final HttpServletResponse response)
+ throws Exception {
+
+
+ final AjaxHandler templateAjaxHandler = getAjaxHandler();
+
+ if (templateAjaxHandler == null) {
+ throw new ConfigurationException("[THYMELEAF] AJAX Handler set into " +
+ AjaxThymeleafView.class.getSimpleName() + " instance for template " +
+ getTemplateName() + " is null.");
+ }
+
+ if (templateAjaxHandler.isAjaxRequest(request, response)) {
+
+ final Set fragmentsToRender = getRenderFragments(model, request, response);
+ if (fragmentsToRender == null || fragmentsToRender.size() == 0) {
+ vlogger.warn("[THYMELEAF] An Ajax request was detected, but no fragments were specified to be re-rendered. "
+ + "Falling back to full page render. This can cause unpredictable results when processing "
+ + "the ajax response on the client.");
+ super.render(model, request, response);
+ return;
+ }
+
+ super.renderFragment(fragmentsToRender, model, request, response);
+
+ } else {
+
+ super.render(model, request, response);
+
+ }
+
+ }
+
+
+
+
+ @SuppressWarnings({ "rawtypes", "unused" })
+ protected Set getRenderFragments(
+ final Map model, final HttpServletRequest request, final HttpServletResponse response) {
+ final String fragmentsParam = request.getParameter(FRAGMENTS_PARAM);
+ final String[] renderFragments = StringUtils.commaDelimitedListToStringArray(fragmentsParam);
+ if (renderFragments.length == 0) {
+ return null;
+ }
+ if (renderFragments.length == 1) {
+ return Collections.singleton(renderFragments[0]);
+ }
+ return new HashSet(Arrays.asList(renderFragments));
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/booking-mvc/src/main/java/org/thymeleaf/spring6/view/AjaxThymeleafViewResolver.java b/booking-mvc/src/main/java/org/thymeleaf/spring6/view/AjaxThymeleafViewResolver.java
new file mode 100644
index 0000000..c654551
--- /dev/null
+++ b/booking-mvc/src/main/java/org/thymeleaf/spring6/view/AjaxThymeleafViewResolver.java
@@ -0,0 +1,192 @@
+/*
+ * =============================================================================
+ *
+ * Copyright (c) 2011-2018, The THYMELEAF team (http://www.thymeleaf.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * =============================================================================
+ */
+package org.thymeleaf.spring6.view;
+
+import java.io.IOException;
+import java.util.Locale;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.thymeleaf.exceptions.ConfigurationException;
+
+import org.springframework.web.servlet.View;
+import org.springframework.web.servlet.view.RedirectView;
+import org.springframework.webflow.context.servlet.AjaxHandler;
+import org.springframework.webflow.context.servlet.DefaultAjaxHandler;
+
+
+// Copied from thymeleaf-spring5.
+// Temporarily here until available in thymeleaf-spring6.
+
+
+/**
+ *
+ * Subclass of {@link ThymeleafViewResolver} adding compatibility with AJAX-based events
+ * (redirects) in Spring WebFlow.
+ *
+ *
+ * Important: Spring WebFlow dependencies are OPTIONAL. If you are not using WebFlow
+ * in your application, then you should be using {@link ThymeleafViewResolver} directly.
+ *
+ * Return the AJAX handler (from Spring Javascript) used
+ * to determine whether a request is an AJAX request or not
+ * in views resolved by this resolver.
+ *
+ *
+ * An instance of {@link DefaultAjaxHandler} is set by default.
+ *
+ * Sets the AJAX handler (from Spring Javascript) used
+ * to determine whether a request is an AJAX request or not
+ * in views resolved by this resolver.
+ *
+ *
+ * An instance of {@link DefaultAjaxHandler} is set by default.
+ *
+ *
+ * @param ajaxHandler the AJAX handler.
+ */
+ public void setAjaxHandler(final AjaxHandler ajaxHandler) {
+ this.ajaxHandler = ajaxHandler;
+ }
+
+
+
+
+ @Override
+ protected View createView(final String viewName, final Locale locale) throws Exception {
+
+ if (!canHandle(viewName, locale)) {
+ return null;
+ }
+
+ if (this.ajaxHandler == null) {
+ throw new ConfigurationException("[THYMELEAF] AJAX Handler set into " +
+ AjaxThymeleafViewResolver.class.getSimpleName() + " instance is null.");
+ }
+
+ // Check for special "redirect:" prefix.
+ if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
+ vrlogger.trace(
+ "[THYMELEAF] View {} is a redirect. An AJAX-enabled RedirectView implementation will " +
+ "be handling the request.", viewName);
+ final String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
+ return new AjaxRedirectView(
+ this.ajaxHandler, redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
+ }
+
+ final View view = super.createView(viewName, locale);
+
+ if (view instanceof AjaxEnabledView) {
+ // Set the AJAX handler into view, if it is an AjaxThymeleafView.
+
+ final AjaxEnabledView ajaxEnabledView = (AjaxEnabledView) view;
+
+ if (ajaxEnabledView.getAjaxHandler() == null && getAjaxHandler() != null) {
+ ajaxEnabledView.setAjaxHandler(getAjaxHandler());
+ }
+
+ }
+
+ return view;
+
+ }
+
+
+
+
+
+ private static class AjaxRedirectView extends RedirectView {
+
+ private static final Logger vlogger = LoggerFactory.getLogger(AjaxRedirectView.class);
+
+ private AjaxHandler ajaxHandler = new DefaultAjaxHandler();
+
+ AjaxRedirectView(final AjaxHandler ajaxHandler, final String redirectUrl,
+ final boolean redirectContextRelative, final boolean redirectHttp10Compatible) {
+ super(redirectUrl, redirectContextRelative, redirectHttp10Compatible);
+ this.ajaxHandler = ajaxHandler;
+ }
+
+ @Override
+ protected void sendRedirect(final HttpServletRequest request, final HttpServletResponse response,
+ final String targetUrl, final boolean http10Compatible)
+ throws IOException {
+
+ if (this.ajaxHandler == null) {
+ throw new ConfigurationException("[THYMELEAF] AJAX Handler set into " +
+ AjaxThymeleafViewResolver.class.getSimpleName() + " instance is null.");
+ }
+
+ if (this.ajaxHandler.isAjaxRequest(request, response)) {
+ if (vlogger.isTraceEnabled()) {
+ vlogger.trace(
+ "[THYMELEAF] RedirectView for URL \"{}\" is an AJAX request. AjaxHandler of class {} " +
+ "will be in charge of processing the request.", targetUrl, this.ajaxHandler.getClass().getName());
+ }
+ this.ajaxHandler.sendAjaxRedirect(targetUrl, request, response, false);
+ } else {
+ vlogger.trace(
+ "[THYMELEAF] RedirectView for URL \"{}\" is not an AJAX request. Request will be handled " +
+ "as a normal redirect", targetUrl);
+ super.sendRedirect(request, response, targetUrl, http10Compatible);
+ }
+ }
+
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/booking-mvc/src/main/java/org/thymeleaf/spring6/view/FlowAjaxThymeleafView.java b/booking-mvc/src/main/java/org/thymeleaf/spring6/view/FlowAjaxThymeleafView.java
new file mode 100644
index 0000000..ed29e39
--- /dev/null
+++ b/booking-mvc/src/main/java/org/thymeleaf/spring6/view/FlowAjaxThymeleafView.java
@@ -0,0 +1,93 @@
+/*
+ * =============================================================================
+ *
+ * Copyright (c) 2011-2018, The THYMELEAF team (http://www.thymeleaf.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * =============================================================================
+ */
+package org.thymeleaf.spring6.view;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.springframework.webflow.execution.RequestContext;
+import org.springframework.webflow.execution.RequestContextHolder;
+import org.springframework.webflow.execution.View;
+
+
+// Copied from thymeleaf-spring5.
+// Temporarily here until available in thymeleaf-spring6.
+
+
+/**
+ *
+ * Subclass of {@link AjaxThymeleafView} for Spring WebFlow,
+ * designed for obtaining the fragments to be rendered via
+ * AJAX in the way needed by Spring WebFlow.
+ *
+ *
+ * Most people will need to use this class instead of
+ * {@link AjaxThymeleafView} if you are using Spring WebFlow.
+ *
+ *
+ * @author Daniel Fernández
+ *
+ * @since 3.0.3
+ *
+ */
+public class FlowAjaxThymeleafView extends AjaxThymeleafView {
+
+
+
+
+
+ public FlowAjaxThymeleafView() {
+ super();
+ }
+
+
+
+
+
+ @Override
+ @SuppressWarnings("rawtypes")
+ protected Set getRenderFragments(
+ final Map model, final HttpServletRequest request, final HttpServletResponse response) {
+
+ final RequestContext context = RequestContextHolder.getRequestContext();
+ if (context == null) {
+ return super.getRenderFragments(model, request, response);
+ }
+
+ final String[] fragments = (String[]) context.getFlashScope().get(View.RENDER_FRAGMENTS_ATTRIBUTE);
+ if (fragments == null || fragments.length == 0) {
+ return super.getRenderFragments(model, request, response);
+ }
+ if (fragments.length == 1) {
+ return Collections.singleton(fragments[0]);
+ }
+ return new HashSet(Arrays.asList(fragments));
+
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/booking-mvc/src/main/resources/log4j2.xml b/booking-mvc/src/main/resources/log4j2.xml
index f495463..22aa0ba 100644
--- a/booking-mvc/src/main/resources/log4j2.xml
+++ b/booking-mvc/src/main/resources/log4j2.xml
@@ -7,6 +7,8 @@
+
+
diff --git a/booking-mvc/src/main/webapp/WEB-INF/hotels/booking/booking-flow.xml b/booking-mvc/src/main/webapp/WEB-INF/hotels/booking/booking-flow.xml
index d166884..be94c71 100644
--- a/booking-mvc/src/main/webapp/WEB-INF/hotels/booking/booking-flow.xml
+++ b/booking-mvc/src/main/webapp/WEB-INF/hotels/booking/booking-flow.xml
@@ -13,7 +13,7 @@
-
+
@@ -32,7 +32,7 @@
-
+
diff --git a/booking-mvc/src/main/webapp/WEB-INF/hotels/booking/enterBookingDetails.html b/booking-mvc/src/main/webapp/WEB-INF/hotels/booking/enterBookingDetails.html
new file mode 100644
index 0000000..db4f37d
--- /dev/null
+++ b/booking-mvc/src/main/webapp/WEB-INF/hotels/booking/enterBookingDetails.html
@@ -0,0 +1,255 @@
+
+
+
+
+
+
+
+
+
+ Spring Travel: Spring MVC and Web Flow Reference Application
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+