Skip to content

Commit 6f82ff3

Browse files
committed
Switch from JSP to Thymeleaf views
This is a revert of commit 758596 which did the opposite, "temporarily" while Thymeleaf support wasn't yet available.
1 parent 2b42fa3 commit 6f82ff3

30 files changed

+1408
-653
lines changed

booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/WebFlowConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public FlowBuilderServices flowBuilderServices() {
4545
@Bean
4646
public MvcViewFactoryCreator mvcViewFactoryCreator() {
4747
MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
48-
factoryCreator.setViewResolvers(Collections.singletonList(this.webMvcConfig.viewResolver()));
48+
factoryCreator.setViewResolvers(Collections.singletonList(this.webMvcConfig.tilesViewResolver()));
4949
factoryCreator.setUseSpringBeanBinding(true);
5050
return factoryCreator;
5151
}

booking-mvc/src/main/java/org/springframework/webflow/samples/booking/config/WebMvcConfig.java

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,32 @@
11
package org.springframework.webflow.samples.booking.config;
22

3+
import java.util.LinkedHashSet;
4+
import java.util.Set;
5+
36
import org.springframework.beans.factory.annotation.Autowired;
47
import org.springframework.context.annotation.Bean;
58
import org.springframework.context.annotation.Configuration;
69
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
710
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
811
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
912
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
10-
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
11-
import org.springframework.web.servlet.view.InternalResourceViewResolver;
12-
import org.springframework.web.servlet.view.UrlBasedViewResolver;
13+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
1314
import org.springframework.webflow.mvc.servlet.FlowHandlerAdapter;
1415
import org.springframework.webflow.mvc.servlet.FlowHandlerMapping;
1516
import org.springframework.webflow.samples.booking.BookingFlowHandler;
17+
import org.thymeleaf.dialect.IDialect;
18+
import org.thymeleaf.extras.conditionalcomments.dialect.ConditionalCommentsDialect;
19+
import org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect;
20+
import org.thymeleaf.extras.tiles2.dialect.TilesDialect;
21+
import org.thymeleaf.extras.tiles2.spring4.web.configurer.ThymeleafTilesConfigurer;
22+
import org.thymeleaf.extras.tiles2.spring4.web.view.FlowAjaxThymeleafTilesView;
23+
import org.thymeleaf.spring4.SpringTemplateEngine;
24+
import org.thymeleaf.spring4.view.AjaxThymeleafViewResolver;
25+
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
1626

1727
@EnableWebMvc
1828
@Configuration
19-
public class WebMvcConfig implements WebMvcConfigurer {
29+
public class WebMvcConfig extends WebMvcConfigurerAdapter {
2030

2131
@Autowired
2232
private WebFlowConfig webFlowConfig;
@@ -60,8 +70,40 @@ public BookingFlowHandler BookingFlowHandler() {
6070
}
6171

6272
@Bean
63-
public UrlBasedViewResolver viewResolver() {
64-
return new InternalResourceViewResolver();
73+
public AjaxThymeleafViewResolver tilesViewResolver() {
74+
AjaxThymeleafViewResolver viewResolver = new AjaxThymeleafViewResolver();
75+
viewResolver.setViewClass(FlowAjaxThymeleafTilesView.class);
76+
viewResolver.setTemplateEngine(templateEngine());
77+
return viewResolver;
78+
}
79+
80+
@Bean
81+
public SpringTemplateEngine templateEngine(){
82+
83+
Set<IDialect> dialects = new LinkedHashSet<IDialect>();
84+
dialects.add(new TilesDialect());
85+
dialects.add(new SpringSecurityDialect());
86+
dialects.add(new ConditionalCommentsDialect());
87+
88+
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
89+
templateEngine.setTemplateResolver(templateResolver());
90+
templateEngine.setAdditionalDialects(dialects);
91+
return templateEngine;
92+
}
93+
94+
@Bean
95+
public ServletContextTemplateResolver templateResolver() {
96+
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
97+
templateResolver.setPrefix("/WEB-INF");
98+
templateResolver.setTemplateMode("HTML5");
99+
return templateResolver;
100+
}
101+
102+
@Bean
103+
public ThymeleafTilesConfigurer tilesConfigurer() {
104+
ThymeleafTilesConfigurer configurer = new ThymeleafTilesConfigurer();
105+
configurer.setDefinitions("/WEB-INF/**/views.xml");
106+
return configurer;
65107
}
66108

67109
}
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
<!DOCTYPE html>
2+
<html xmlns="http://www.w3.org/1999/xhtml"
3+
xmlns:th="http://www.thymeleaf.org"
4+
xmlns:tiles="http://www.thymeleaf.org"
5+
xmlns:sec="http://www.thymeleaf.org"
6+
lang="en">
7+
8+
<head>
9+
10+
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
11+
<!-- This <head> section is only used for static prototyping purposes. At runtime, -->
12+
<!-- Tiles will only use the body fragment defined with tiles:fragment="content", -->
13+
<!-- as specified at the corresponding views.xml file. -->
14+
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
15+
16+
<title>Spring Travel: Spring MVC and Web Flow Reference Application</title>
17+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
18+
19+
<link rel="stylesheet" type="text/css" media="screen, projection"
20+
href="../../../styles/blueprint/screen.css" />
21+
22+
<link rel="stylesheet" type="text/css" media="print"
23+
href="../../../styles/blueprint/print.css" />
24+
25+
<!--[if lt IE 8]>
26+
<link rel="stylesheet" type="text/css" media="screen, projection"
27+
href="../../../styles/blueprint/ie.css" />
28+
<![endif]-->
29+
30+
<link rel="stylesheet" type="text/css" media="screen"
31+
href="../../../styles/booking.css" />
32+
33+
34+
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
35+
<!-- Some styles and scripts are served from spring-js-resources-{ver}.jar at -->
36+
<!-- runtime. Therefore not available for static prototyping. See the -->
37+
<!-- layouts/standard.html template file for detail. -->
38+
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
39+
40+
</head>
41+
42+
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
43+
<!-- START of the content to be included in the execution result. -->
44+
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
45+
<!-- Only the markup inside this <body> would be required in this -->
46+
<!-- template if no static prototyping was intended. -->
47+
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
48+
<body tiles:fragment="content">
49+
50+
51+
52+
<div id="bookingForm">
53+
54+
<div class="span-5">
55+
56+
<h3 th:text="${booking.hotel.name}">The Herb Plaza</h3>
57+
58+
<address th:object="${booking.hotel}">
59+
<span th:text="*{address}">Thyme Square, 13</span>
60+
<br />
61+
<span th:text="*{city}">Icetown</span>,
62+
<span th:text="*{state}">North Pole</span>,
63+
<span th:text="*{zip}">0W</span>
64+
<br />
65+
<span th:text="*{country}">Earth</span>
66+
</address>
67+
68+
<p>
69+
Nightly rate: <span th:text="${booking.hotel.price}">400.00</span>
70+
</p>
71+
72+
</div>
73+
74+
<div class="span-12">
75+
76+
<form id="booking" action="#" th:object="${booking}" th:action="${flowExecutionUrl}" method="post">
77+
78+
<div class="error" th:if="${#fields.hasErrors('*')}">
79+
<span th:each="err : ${#fields.errors('*')}">
80+
<span th:text="${err}">Input is incorrect</span><br />
81+
</span>
82+
</div>
83+
84+
<fieldset>
85+
<legend>Book Hotel</legend>
86+
<div>
87+
<div class="span-4">
88+
<label for="checkinDate">Check In:</label>
89+
</div>
90+
<div class="span-7 last">
91+
<p><input type="text" th:field="*{checkinDate}" /></p>
92+
<script type="text/javascript">
93+
// <![CDATA[
94+
Spring.addDecoration(new Spring.ElementDecoration({
95+
elementId : "checkinDate",
96+
widgetType : "dijit.form.DateTextBox",
97+
widgetAttrs : { datePattern : "MM-dd-yyyy", required : true }}));
98+
// ]]>
99+
</script>
100+
101+
</div>
102+
</div>
103+
<div>
104+
<div class="span-4">
105+
<label for="checkoutDate">Check Out:</label>
106+
</div>
107+
<div class="span-7 last">
108+
<p><input type="text" th:field="*{checkoutDate}" /></p>
109+
<script type="text/javascript">
110+
// <![CDATA[
111+
Spring.addDecoration(new Spring.ElementDecoration({
112+
elementId : "checkoutDate",
113+
widgetType : "dijit.form.DateTextBox",
114+
widgetAttrs : { datePattern : "MM-dd-yyyy", required : true }}));
115+
// ]]>
116+
</script>
117+
</div>
118+
</div>
119+
<div>
120+
<div class="span-4">
121+
<label for="beds">Room Preference:</label>
122+
</div>
123+
<div class="span-7 last">
124+
<p>
125+
<select th:field="*{beds}">
126+
<option label="One king-size bed" value="1">One king-size bed</option>
127+
<option label="Two double beds" value="2" >Two double beds</option>
128+
<option label="Three beds" value="3" >Three beds</option>
129+
</select>
130+
</p>
131+
</div>
132+
</div>
133+
<div>
134+
<div class="label span-4">
135+
Smoking Preference:
136+
</div>
137+
<div id="radio" class="span-7 last">
138+
<p>
139+
<input type="radio" id="smoking" th:field="*{smoking}" value="true" /><label for="smoking">Smoking</label>
140+
<input type="radio" id="non-smoking" th:field="*{smoking}" value="false" /><label for="non-smoking">Non Smoking</label>
141+
</p>
142+
<script type="text/javascript">
143+
// <![CDATA[
144+
Spring.addDecoration(new Spring.ElementDecoration({
145+
elementId : 'smoking',
146+
widgetType : "dijit.form.RadioButton",
147+
widgetModule : "dijit.form.CheckBox",
148+
widgetAttrs : { value : "true" }
149+
}));
150+
Spring.addDecoration(new Spring.ElementDecoration({
151+
elementId : 'non-smoking',
152+
widgetType : "dijit.form.RadioButton",
153+
widgetModule : "dijit.form.CheckBox",
154+
widgetAttrs : { value : "false" }
155+
}));
156+
// ]]>
157+
</script>
158+
</div>
159+
</div>
160+
<div>
161+
<div class="label span-4">
162+
Amenities:
163+
</div>
164+
<div id="amenities" class="span-7 last">
165+
<p>
166+
<input type="checkbox" th:field="*{amenities}" value="OCEAN_VIEW" /><label th:for="${#ids.prev('amenities')}">Ocean View</label>
167+
<br />
168+
<input type="checkbox" th:field="*{amenities}" value="LATE_CHECKOUT" /><label th:for="${#ids.prev('amenities')}">Late Checkout</label>
169+
<br />
170+
<input type="checkbox" th:field="*{amenities}" value="MINIBAR" /><label th:for="${#ids.prev('amenities')}">Minibar</label>
171+
</p>
172+
<script type="text/javascript">
173+
// <![CDATA[
174+
dojo.query("#amenities input[type='checkbox']").forEach(function(element){
175+
Spring.addDecoration(new Spring.ElementDecoration({
176+
elementId: element.id,
177+
widgetType : "dijit.form.CheckBox",
178+
widgetAttrs : { checked : element.checked }
179+
}));
180+
});
181+
// ]]>
182+
</script>
183+
</div>
184+
</div>
185+
<div>
186+
<div class="span-4">
187+
<label for="creditCard">Credit Card #:</label>
188+
</div>
189+
<div class="span-7 last">
190+
<p><input type="text" th:field="*{creditCard}" /></p>
191+
<script type="text/javascript">
192+
// <![CDATA[
193+
Spring.addDecoration(new Spring.ElementDecoration({
194+
elementId : "creditCard",
195+
widgetType : "dijit.form.ValidationTextBox",
196+
widgetAttrs : { required : true, invalidMessage : "A 16-digit credit card number is required.",
197+
regExp : "[0-9]{16}" }}));
198+
// ]]>
199+
</script>
200+
</div>
201+
</div>
202+
<div>
203+
<div class="span-4">
204+
<label for="creditCardName">Credit Card Name:</label>
205+
</div>
206+
<div class="span-7 last">
207+
<p><input type="text" th:field="*{creditCardName}" maxlength="40" /></p>
208+
<script type="text/javascript">
209+
// <![CDATA[
210+
Spring.addDecoration(new Spring.ElementDecoration({
211+
elementId : "creditCardName",
212+
widgetType : "dijit.form.ValidationTextBox",
213+
widgetAttrs : { required : true }}));
214+
// ]]>
215+
</script>
216+
</div>
217+
</div>
218+
<div>
219+
<div class="span-4">
220+
<label for="creditCardExpiryMonth">Expiration Date:</label>
221+
</div>
222+
<div class="span-7 last">
223+
<p>
224+
<select th:field="*{creditCardExpiryMonth}">
225+
<option value="1">Jan</option>
226+
<option value="2">Feb</option>
227+
<option value="3">Mar</option>
228+
<option value="4">Apr</option>
229+
<option value="5">May</option>
230+
<option value="6">Jun</option>
231+
<option value="7">Jul</option>
232+
<option value="8">Aug</option>
233+
<option value="9">Sep</option>
234+
<option value="10">Oct</option>
235+
<option value="11">Nov</option>
236+
<option value="12">Dec</option>
237+
</select>
238+
<select th:field="*{creditCardExpiryYear}">
239+
<option value="1">2008</option>
240+
<option value="2">2009</option>
241+
<option value="3">2010</option>
242+
<option value="4">2011</option>
243+
<option value="5">2012</option>
244+
</select>
245+
</p>
246+
</div>
247+
</div>
248+
<div>
249+
<p>
250+
<button type="submit" id="proceed" name="_eventId_proceed">Proceed</button>
251+
<button type="submit" name="_eventId_cancel" >Cancel</button>
252+
</p>
253+
<script type="text/javascript">
254+
// <![CDATA[
255+
Spring.addDecoration(new Spring.ValidateAllDecoration({elementId:'proceed', event:'onclick'}));
256+
Spring.addDecoration(new Spring.AjaxEventDecoration({elementId:'proceed',event:'onclick',formId:'booking'}));
257+
// ]]>
258+
</script>
259+
</div>
260+
</fieldset>
261+
262+
</form>
263+
264+
</div>
265+
266+
</div>
267+
268+
269+
</body>
270+
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
271+
<!-- END of the content to be included in the execution result -->
272+
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
273+
274+
</html>

0 commit comments

Comments
 (0)