SWF-1219 Update booking-mvc sample to use template URLs with path variables, the Spring MVC namespace, the HiddenHttpMethodFilter, and the spring:url tag.

This commit is contained in:
Rossen Stoyanchev
2010-05-05 20:48:18 +00:00
parent 6f48e5badc
commit 9fd402fbc7
17 changed files with 134 additions and 128 deletions

View File

@@ -10,16 +10,18 @@ import org.springframework.webflow.mvc.servlet.AbstractFlowHandler;
public class BookingFlowHandler extends AbstractFlowHandler {
private static final String DEFAULT_URL = "/hotels/search";
@Override
public String handleExecutionOutcome(FlowExecutionOutcome outcome, HttpServletRequest request,
HttpServletResponse response) {
return "/hotels/index";
return DEFAULT_URL;
}
@Override
public String handleException(FlowException e, HttpServletRequest request, HttpServletResponse response) {
if (e instanceof NoSuchFlowExecutionException) {
return "/hotels/index";
return DEFAULT_URL;
} else {
throw e;
}

View File

@@ -6,9 +6,9 @@ import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class HotelsController {
@@ -20,30 +20,31 @@ public class HotelsController {
this.bookingService = bookingService;
}
@RequestMapping(method = RequestMethod.GET)
public void index(SearchCriteria searchCriteria, Principal currentUser, Model model) {
@RequestMapping(value = "/hotels/search", method = RequestMethod.GET)
public void search(SearchCriteria searchCriteria, Principal currentUser, Model model) {
if (currentUser != null) {
List<Booking> booking = bookingService.findBookings(currentUser.getName());
model.addAttribute(booking);
}
}
@RequestMapping(method = RequestMethod.GET)
public String search(SearchCriteria criteria, Model model) {
@RequestMapping(value = "/hotels", method = RequestMethod.GET)
public String list(SearchCriteria criteria, Model model) {
List<Hotel> hotels = bookingService.findHotels(criteria);
model.addAttribute(hotels);
return "hotels/search";
return "hotels/list";
}
@RequestMapping(method = RequestMethod.GET)
public Hotel show(@RequestParam("id") Long id) {
return bookingService.findHotelById(id);
@RequestMapping(value = "/hotels/{id}", method = RequestMethod.GET)
public String show(@PathVariable Long id, Model model) {
model.addAttribute(bookingService.findHotelById(id));
return "hotels/show";
}
@RequestMapping(method = RequestMethod.GET)
public String deleteBooking(@RequestParam("id") Long id) {
@RequestMapping(value = "/bookings/{id}", method = RequestMethod.DELETE)
public String deleteBooking(@PathVariable Long id) {
bookingService.cancelBooking(id);
return "redirect:index";
return "redirect:../hotels/search";
}
}

View File

@@ -11,7 +11,7 @@
<!-- Configure Spring Security -->
<security:http auto-config="true">
<security:form-login login-page="/spring/login" login-processing-url="/spring/loginProcess"
default-target-url="/spring/hotels/index" authentication-failure-url="/spring/login?login_error=1" />
default-target-url="/spring/hotels/search" authentication-failure-url="/spring/login?login_error=1" />
<security:logout logout-url="/spring/logout" logout-success-url="/spring/logoutSuccess" />
</security:http>

View File

@@ -5,20 +5,19 @@
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Maps request paths to flows in the flowRegistry; e.g. a path of /hotels/booking looks for a flow with id "hotels/booking" -->
<!-- Enables controllers mapped with @RequestMapping annotations, formatting annotations @NumberFormat @DateTimeFormat, and JSR 303 style validation -->
<mvc:annotation-driven/>
<!-- Maps request paths to flows in the flowRegistry; e.g. a path of /hotels/booking looks for a flow with id "hotels/booking". -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="order" value="0" />
<property name="order" value="-1"/>
<property name="flowRegistry" ref="flowRegistry" />
</bean>
<!-- Maps request paths to @Controller classes; e.g. a path of /hotels looks for a controller named HotelsController -->
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
<property name="order" value="1" />
<property name="defaultHandler">
<!-- If no @Controller match, map path to a view to render; e.g. the "/intro" path would map to the view named "intro" -->
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
</property>
</bean>
<!-- Map paths directly to view names without controller processing. Use the view-name attribute if necessary: by convention the view name equals the path without the leading slash -->
<mvc:view-controller path="/intro" />
<mvc:view-controller path="/login" />
<mvc:view-controller path="/logoutSuccess" />
<!-- Resolves logical view names returned by Controllers to Tiles; a view name to resolve is treated as the name of a tiles definition -->
<bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">
@@ -35,12 +34,6 @@
</property>
</bean>
<!-- Dispatches requests mapped to POJO @Controllers implementations -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<!-- Dispatches requests mapped to org.springframework.web.servlet.mvc.Controller implementations -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
<!-- Dispatches requests mapped to flows to FlowHandler implementations -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor"/>

View File

@@ -35,7 +35,7 @@
<transition on="cancel" to="cancel" />
</view-state>
<end-state id="bookingConfirmed" commit="true" view="externalRedirect:servletRelative:/hotels/index" />
<end-state id="bookingConfirmed" commit="true" />
<end-state id="cancel" />

View File

@@ -1,5 +1,7 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<div id="bookings" "class="section">
<security:authorize ifAllGranted="ROLE_USER">
@@ -34,14 +36,12 @@
<td>${booking.checkoutDate}</td>
<td>${booking.id}</td>
<td>
<a id="cancelLink_${booking.id}" href="deleteBooking?id=${booking.id}">Cancel</a>
<script type="text/javascript">
Spring.addDecoration(new Spring.AjaxEventDecoration({
elementId:"cancelLink_${booking.id}",
event:"onclick",
params: {fragments:"bookingsTable"}
}));
</script>
<spring:url var="bookingUrl" value="/spring/bookings/{id}">
<spring:param name="id" value="${booking.id}"/>
</spring:url>
<form:form action="${bookingUrl}" method="delete">
<button type="submit">Cancel</button>
</form:form>
</td>
</tr>
</c:forEach>

View File

@@ -1,6 +1,8 @@
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<form:form modelAttribute="searchCriteria" action="search" method="get">
<c:url var="hotelsUrl" value="/spring/hotels"/>
<form:form modelAttribute="searchCriteria" action="${hotelsUrl}" method="get">
<div class="section">
<span class="errors">
<form:errors path="*"/>

View File

@@ -1,5 +0,0 @@
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<tiles:insertAttribute name="hotelSearchForm" />
<tiles:insertAttribute name="bookingsTable" />

View File

@@ -0,0 +1,72 @@
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<div id="heading" class="section">
<h2>Hotel Results</h2>
</div>
<p>
<a id="changeSearchLink" href="hotels/search?searchString=${searchCriteria.searchString}&pageSize=${searchCriteria.pageSize}">Change Search</a>
<script type="text/javascript">
Spring.addDecoration(new Spring.AjaxEventDecoration({
elementId: "changeSearchLink",
event: "onclick",
popup: true,
params: {fragments: "hotelSearchForm"}
}));
</script>
</p>
<div id="hotelResults" class="section">
<c:if test="${not empty hotelList}">
<table class="summary">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>City, State</th>
<th>Zip</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<c:forEach var="hotel" items="${hotelList}">
<tr>
<td>${hotel.name}</td>
<td>${hotel.address}</td>
<td>${hotel.city}, ${hotel.state}, ${hotel.country}</td>
<td>${hotel.zip}</td>
<td><a href="hotels/${hotel.id}">View Hotel</a></td>
</tr>
</c:forEach>
<c:if test="${empty hotelList}">
<tr>
<td colspan="5">No hotels found</td>
</tr>
</c:if>
</tbody>
</table>
<div class="buttonGroup">
<c:if test="${searchCriteria.page > 0}">
<a id="prevResultsLink" href="hotels?searchString=${searchCriteria.searchString}&pageSize=${searchCriteria.pageSize}&page=${searchCriteria.page - 1}">Previous Results</a>
<script type="text/javascript">
Spring.addDecoration(new Spring.AjaxEventDecoration({
elementId: "prevResultsLink",
event: "onclick",
params: {fragments: "body"}
}));
</script>
</c:if>
<c:if test="${not empty hotelList && fn:length(hotelList) == searchCriteria.pageSize}">
<a id="moreResultsLink" href="hotels?searchString=${searchCriteria.searchString}&pageSize=${searchCriteria.pageSize}&page=${searchCriteria.page + 1}">More Results</a>
<script type="text/javascript">
Spring.addDecoration(new Spring.AjaxEventDecoration({
elementId: "moreResultsLink",
event: "onclick",
params: {fragments: "body"}
}));
</script>
</c:if>
</div>
</c:if>
</div>

View File

@@ -1,72 +1,5 @@
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<div id="heading" class="section">
<h2>Hotel Results</h2>
</div>
<p>
<a id="changeSearchLink" href="index?searchString=${searchCriteria.searchString}&pageSize=${searchCriteria.pageSize}">Change Search</a>
<script type="text/javascript">
Spring.addDecoration(new Spring.AjaxEventDecoration({
elementId: "changeSearchLink",
event: "onclick",
popup: true,
params: {fragments: "hotelSearchForm"}
}));
</script>
</p>
<div id="hotelResults" class="section">
<c:if test="${not empty hotelList}">
<table class="summary">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>City, State</th>
<th>Zip</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<c:forEach var="hotel" items="${hotelList}">
<tr>
<td>${hotel.name}</td>
<td>${hotel.address}</td>
<td>${hotel.city}, ${hotel.state}, ${hotel.country}</td>
<td>${hotel.zip}</td>
<td><a href="show?id=${hotel.id}">View Hotel</a></td>
</tr>
</c:forEach>
<c:if test="${empty hotelList}">
<tr>
<td colspan="5">No hotels found</td>
</tr>
</c:if>
</tbody>
</table>
<div class="buttonGroup">
<c:if test="${searchCriteria.page > 0}">
<a id="prevResultsLink" href="search?searchString=${searchCriteria.searchString}&pageSize=${searchCriteria.pageSize}&page=${searchCriteria.page - 1}">Previous Results</a>
<script type="text/javascript">
Spring.addDecoration(new Spring.AjaxEventDecoration({
elementId: "prevResultsLink",
event: "onclick",
params: {fragments: "body"}
}));
</script>
</c:if>
<c:if test="${not empty hotelList && fn:length(hotelList) == searchCriteria.pageSize}">
<a id="moreResultsLink" href="search?searchString=${searchCriteria.searchString}&pageSize=${searchCriteria.pageSize}&page=${searchCriteria.page + 1}">More Results</a>
<script type="text/javascript">
Spring.addDecoration(new Spring.AjaxEventDecoration({
elementId: "moreResultsLink",
event: "onclick",
params: {fragments: "body"}
}));
</script>
</c:if>
</div>
</c:if>
</div>
<tiles:insertAttribute name="hotelSearchForm" />
<tiles:insertAttribute name="bookingsTable" />

View File

@@ -7,7 +7,7 @@
</div>
<div class="section">
<form:form id="hotel" modelAttribute="hotel" action="booking" method="post">
<form:form id="hotel" modelAttribute="hotel" action="booking" method="get">
<fieldset>
<div class="field">
<div class="label">Name:</div>

View File

@@ -5,9 +5,9 @@
<tiles-definitions>
<definition name="hotels/index" extends="standardLayout">
<definition name="hotels/search" extends="standardLayout">
<put-attribute name="body">
<definition template="/WEB-INF/hotels/index.jsp">
<definition template="/WEB-INF/hotels/search.jsp">
<put-attribute name="hotelSearchForm" value="/WEB-INF/hotels/hotelSearchForm.jsp" />
<put-attribute name="bookingsTable" value="/WEB-INF/hotels/bookingsTable.jsp" />
</definition>

View File

@@ -23,6 +23,6 @@
<li>Spring IDE tooling integration, with support for graphical flow modeling and visualization</li>
</ul>
<p align="right">
<a href="hotels/index">Start your Spring Travel experience</a>
<a href="hotels/search">Start your Spring Travel experience</a>
</p>
</div>

View File

@@ -48,8 +48,6 @@
<a href="http://www.thespringexperience.com">
<img src="<c:url value="/resources/images/tse.gif"/>" alt="The Spring Experience" />
</a>
<p>
</p>
</div>
<div id="main">
<tiles:insertAttribute name="body" />

View File

@@ -1,8 +1,7 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page import="org.springframework.security.web.authentication.AbstractProcessingFilter" %>
<%@ page import="org.springframework.security.web.authentication.AuthenticationProcessingFilter" %>
<%@ page import="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter" %>
<%@ page import="org.springframework.security.core.AuthenticationException" %>
<h1>Login Required</h1>
@@ -11,7 +10,7 @@
<c:if test="${not empty param.login_error}">
<div class="errors">
Your login attempt was not successful, try again.<br /><br />
Reason: <%= ((AuthenticationException) session.getAttribute(AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY)).getMessage() %>
Reason: <%= ((AuthenticationException) session.getAttribute(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY)).getMessage() %>
</div>
</c:if>
<p>Valid username/passwords are:</p>
@@ -29,7 +28,7 @@
<div class="field">
<div class="label"><label for="j_username">User:</label></div>
<div class="output">
<input type="text" name="j_username" id="j_username" <c:if test="${not empty param.login_error}">value="<%= session.getAttribute(AuthenticationProcessingFilter.SPRING_SECURITY_LAST_USERNAME_KEY) %>"</c:if> />
<input type="text" name="j_username" id="j_username" <c:if test="${not empty param.login_error}">value="<%= session.getAttribute(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY) %>"</c:if> />
<script type="text/javascript">
Spring.addDecoration(new Spring.ElementDecoration({
elementId : "j_username",

View File

@@ -3,5 +3,5 @@
<div class="section">
<h1>Logout</h1>
<p>You have successfully logged out.</p>
<p><a href="<c:url value="hotels/index" />">Continue</a></p>
<p><a href="<c:url value="hotels/search" />">Continue</a></p>
</div>

View File

@@ -11,9 +11,20 @@
/WEB-INF/config/web-application-config.xml
</param-value>
</context-param>
<!-- Enables use of HTTP methods PUT and DELETE -->
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Enables Spring Security -->
<filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>