Spring & JSF integration: Dynamic Navigation
action
attribute of a command to a backing bean:<h:commandButton action="#{bean.actionBasedOnAge}"/>
public String actionBasedOnAge() { if(age < 12) { return "fetchadult"; } else { return "ok" } }
The example above shows how anyone under twelve is directed to 'fetchadult'
instead of the usual 'ok'
. Both the 'fetchadult'
and 'ok'
outcomes will need to have navigation rules defined in the faces-config.xml
so that JSF knows what actual page to display.
When working with Spring MVC it is often more natural to have navigation logic contained in the @Controller
bean. To help with this, implicit 'controller'
and 'handler'
variables are available when rendering JSF from MVC. The 'controller'
variable provides access to the controller bean that was mapped to the original request, and the 'handler'
variable to the underling MVC handler. In Spring 3.0 'controller'
and 'handler'
are generally the same object. In Spring 3.1 however, the underlying MVC architecture is changing and 'handler'
will generally be a org.springframework.web.method.HandlerMethod
instance.
Here is a submit button that references the someNavigation()
method of the the @Controller
:
<h:commandButton action="#{controller.someNavigation"/>
Whilst accessing the controller bean is useful, it is not the ideal solution. I prefer to use logical names in my JSF pages and map those the Java methods. I also want an easy way to get back to data from the underlying model.
The @NavigationMapping
annotation provides another, more flexible approach to handling navigation. It works in a very similar way to @RequestMappings
. The annotation can be placed on any public method in your @Controller
to map navigation outcomes to destinations.
<h:commandButton action="submit"/>
@NavigationMapping public String onSubmit() { return "redirect:http://www.springsource.org"; }
If you need access to a backing bean the standard Spring @Value
annotation can be used. Any EL expression that the page can resolve can also be used on a navigation method parameter.
@NavigationMapping public String onSubmit(@Value("#{person.age}") int age) { ... }
Accessing model elements is even easier. As long as you only have a single object of the type you want to access in your model, and it is not a simple type (int, String, etc), you don’t need any annotations:
@NavigationMapping public String onSubmit(Person p) { ... }
Other argument types can also be used (see the JavaDoc for a complete list). For example, here is a navigation mapping that handles 'submit'
, 'cancel'
and 'save'
outcomes. The injected arguments tell us the which of the three outcomes was clicked and provides access to the source UIComponent
.
@NavigationMapping('submit','cancel','save') public String handleNavigation(String outcome, UIComponent source) { ... }
Return types are also equally flexible. You can return view names as String
s, you can also use the same "@hotelsController.show"
notation that I have previously blogged about. You can also return View object
s directly or you can use NavigationOutcome
if you want to include implicit model items.
Finally, if you just want to render an immediate response you can use the @ResponseBody
annotation or return a HttpEntity
. This works in exactly the same way as Spring.
Reference: Integrating Spring & JavaServer Faces : Dynamic Navigation from our JCG partner Phillip Webb at the Phil Webb’s Blog blog.