Spring MVC with Spring Webflow - java

I am trying to use Spring Webflow with my Spring MVC application.I had a look at the booking-mvc example and followed it,but most of the examples on the web are done with Tiles.I Hope that i am not completely wrong in my understanding and that Spring Webflow can be used with Spring MVC
I am trying to use Spring MVC controllers.But when i am doing a transition like submit/finish nothing seems to happen.
Here is my Flow xml:
<view-state id="enterBookingDetails">
<transition on="submit" to="reviewBooking" />
</view-state>
<view-state id="reviewBooking">
<transition on="confirm" to="bookingConfirmed" />
<transition on="revise" to="enterBookingDetails" />
<transition on="cancel" to="bookingCancelled" />
</view-state>
I Have enterBookingDetails and reviewBooking defined as controllers :
#RequestMapping(value = "/enterBookingDetails", method = RequestMethod.GET)
public ModelAndView getPage(final HttpServletRequest request) {
ModelAndView modelView = new ModelAndView();
modelView.setViewName("pa");
return modelView;
}
#RequestMapping(value = "/reviewBooking", method = RequestMethod.GET)
public ModelAndView getPage2(final HttpServletRequest request) {
ModelAndView modelView = new ModelAndView();
modelView.setViewName("pb");
return modelView;
}
My Jsp looks like this :
<form:form>
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}" />
<input type="hidden" name="_eventId" value="finished" />
<input type="submit" value="Submit" name="_eventId_finished" />
</form:form>
And finally my configuration :
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="mvcViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
<property name="order" value="1" />
</bean>
<!-- Register all Web Flow definitions under /WEB-INF/flows/**/*-flow.xml -->
<webflow:flow-registry id="flowRegistry"
base-path="/WEB-INF/flows" flow-builder-services="flowBuilderServices">
<webflow:flow-location-pattern value="/**/*-flow.xml" />
</webflow:flow-registry>
<!-- Deploy a flow executor -->
<webflow:flow-executor id="flowExecutor" />
<!-- Configure flow builder services -->
<!-- Configure view service -->
<webflow:flow-builder-services id="flowBuilderServices"
view-factory-creator="mvcViewFactoryCreator" />
<!-- Web Flow components -->
<!-- Install flow handler (FlowHandlerAdapter) -->
<!-- It dispatches URL requests to flows -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor" />
</bean>
<!-- Map Http request path to flows register in the registry -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="flowRegistry" ref="flowRegistry" />
<property name="order" value="0" />
</bean>
<bean id="mvcViewFactoryCreator"
class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
<property name="viewResolvers" ref="mvcViewResolver"/>
</bean>

Spring Webflow is built on spring web mvc, so the two can be used together.
I have learned that the problem with this combination is that when there is something misconfigured, the only symptom is "nothing happens". I ultimately ended up looking at the debug logs for org.springframework.web and org.springframework.webflow, then tracing into the spring source code to diagnose configuration issues.
The spring paradigm is aiming towards "convention over configuration". The problem I have had with it is that the conventions are not always well defined in a manner that someone already familiar with them can easily grasp.
The final "gotcha" that I had to resolve is that the convention for spring webflow is to put the flow xml files in the same folder as the jsp's.
In your example, you appear to be planning to switch between spring-webflow and unadorned web mvc behind the same view. Provided everything is correctly configured, for a given uri, whatever is in the webflow registry will trump whatever is in the UrlHandlerMapping (your annotations). This can create confusion if you're not aware of it.

Related

Spring 4.3.3 - ParameterizableViewController POST method not more supported

After upgrading to Spring 4.3.3.RELEASE i get the error:
Request method 'POST' not supported
My application is a basic template and the home view is rendered via
<mvc:view-controller path="/" view-name="home.view"/>
It works fine on Spring 4.2.8.
Any hint to solve the problem?
We ran into the same problem. It turns out that, at some point, the ParameterizableViewController was changed to only support GET and HEAD requests.
We resolved this by replacing the definition with something like this:
<bean id="homeController" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<property name="supportedMethods" value="GET,POST,PUT,DELETE" />
<property name="viewName" value="home.view" />
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<map>
<entry key="/" value-ref="homeController"/>
</map>
</property>
</bean>
Essentially, this allows you to create a ParameterizableViewController with whatever supported HTTP methods you wish. The second bean creates the mapping so that the path "/" resolves to the defined controller.
ParameterizableViewController default supported methods are GET,HEAD we are check it with the following code snippet.
ParameterizableViewController pvc=new ParameterizableViewController();
String[] str=pvc.getSupportedMethods();
for(String x:str) {
System.out.println(x);
}
in order to add POST or any HTTP method, we need to add this XML tag in our bean tag.
<bean id="testUrl"
class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<property name="supportedMethods" value="GET,POST,PUT,DELETE" />
<property name="viewName" value="success" />
</bean>

Spring call Jndi variable to jsp

I have some difficulties to call a JNDI variable to my jsp Page.
Context.xml :
<!-- Environnement de l'application -->
<Environment name="app/env" override="false" type="java.lang.String" value="Développement" />
conf-view-spring.xml
<jee:jndi-lookup id="jndiLookEnv" jndi-name="app/env"
expected-type="java.lang.String" />
footer.jsp
<div class="panel-footer footerstick clearfix">
<div class="pull-right">
<strong><c:out value="${jndiLookEnv}"></c:out></strong>
</div>
</div>
I have no error but my jndiLookEnv is empty,
What's wrong in this case?
Thank you.
Beans in the context aren't accessible by the JSP (or at least not in the way you are trying to). You would need a scriptlet to get access to the ApplicationContext and do a getBean to retrieve the value. Using ${jndiLookEnv} isn't going to work.
To make it available for easy use in the JSP you need to add a ServletContextAttributeExporter to expose it.
<bean class="org.springframework.web.context.suppor.ServletContextAttributeExporter">
<property name="attributes">
<map>
<entry key="env" value-ref="jndiLookEnv" />
</map>
</properties>
</bean>
Now you can use ${env} to reference to value.
Now you can improve on this and remove the JNDI lookup al together (assuming that you are on a recent spring version).
<bean class="org.springframework.web.context.suppor.ServletContextAttributeExporter">
<property name="attributes">
<map>
<entry key="env" value="#{environment['app/env']}" />
</map>
</properties>
</bean>
The Environment abstraction will do a lookup for the property in various locations, one of them being JNDI (you could override the app/env property using properties or a system property for instance.

Spring web flow: the flow XMLs are not being registered

I am using spring webflow and I have registered all the flow xmls in the webflow.xml like this
<!-- The Flow handler adapter, to handle flows request recieved by the dispatcher servlet -->
<bean id="flowController" class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor"/>
</bean>
<flow:flow-registry id="myflowRegistry" flow-builder-services="flowBuilderServices" >
<!-- all xml files in base path and subfolders -->
<flow:flow-location path="/WEB-INF/flows/payslips.xml" />
<flow:flow-location path="/WEB-INF/flows/admissions.xml" />
<flow:flow-location id="cash-advance" path="/WEB-INF/flows/cashadvance.xml"/>
<flow:flow-location path="/WEB-INF/flows/services.xml" />
<flow:flow-location path="/WEB-INF/flows/undergradadm.xml" />
</flow:flow-registry>
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="order" value="0" />
<property name="flowRegistry" ref="myflowRegistry" />
</bean>
Now when I tr to access any of these pages with payslips.go or cash-advance.go they dont work and give me :
Error 500: Request processing failed; nested exception is java.lang.StringIndexOutOfBoundsException: String index out of range: 1
I am very new to webflow and It seems logical that it should work. The views in the spring MVC that are not part of the webflow or dont have any xmls defined under flow work perfectly fine because it has nothing to do with webflow. but these pages which have a flow defined. I dont think mozilla has anything to do with it.
On some other machine, these are working fine. there must be something with my own setup that its not letting it work.
May be this will help as well
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: 1
at java.lang.String.substring(String.java:1060)
at org.springframework.webflow.context.servlet.DefaultFlowUrlHandler.getFlowId(DefaultFlowUrlHandler.java:83)
at org.springframework.webflow.mvc.servlet.FlowHandlerMapping.getHandlerInternal(FlowHandlerMapping.java:92)
at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:184)
at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1057)
Thanks
This is how I am configuring SWF:
<!--
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SPRING WEB FLOW'S CONFIGURATION
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-->
<!-- Creates a flow executor in Spring, responsible for creating and executing flows -->
<flow:flow-executor id="flowExecutor" flow-registry="flowRegistry" />
<!-- Load flow definitions and make them available to the flow executor -->
<flow:flow-registry id="flowRegistry">
<flow:flow-location id="process-flow" path="/process/flows/process-flow.xml" />
</flow:flow-registry>
<!-- The FlowHandlerMapping helps DispatcherServlet to knowing that it should send flow requests to Spring Web Flow -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="flowRegistry" ref="flowRegistry" />
</bean>
<!-- The FlowHandlerAdapter is equivalent to a Spring MVC controller in that it handles requests coming in for a flow and processes those requests -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor" />
</bean>
My flow is in the root of my web folder, but you can also use the WEB-INF dir; this way, the path should be "/WEB-INF/foo/bar.xml/".
I hope it helps, regards.

Using VelocityView or plain text in Controller response?

I'm trying to return content other than json in my Controller, but I can't seem to get it to work. Ideally, I'd like to return a rendered velocity template as plain text or html.
This is what I have in my controller:
#RequestMapping( value = "time", headers = "Accept=*/*", method = RequestMethod.GET )
public #ResponseBody
Date getCurrentTime( HttpServletRequest request, HttpServletResponse response ) {
response.setContentType( "text/plain" );
return new Date();
}
And this is in my springmvc-servlet.xml (I know this is not right...but I'm a bit lost here):
<context:component-scan base-package="com.paml.alerter.controller" />
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="cache" value="true" />
<property name="prefix" value="" />
<property name="suffix" value=".vm" />
</bean>
<!-- This bean sets up the Velocity environment for us based on a root path
for templates. Optionally, a properties file can be specified for more control
over the Velocity environment, but the defaults are pretty sane for file
based template loading. -->
<bean id="velocityConfig"
class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/WEB-INF/velocity/" />
</bean>
Does anyone know how to set this up right?
TIA
If your method is annotated with #ResponseBody, then the Spring MVC view layer will be bypassed entirely.
If you're not interested in JSON output, then #ResponseBody is inappropriate - just remove it, and your Velocity views will be used.
If you need to switch between JSON and some other View layer, then you should consider removing #ResponseBody and using ContentNegotiatingViewResolver instead. See the Spring docs for how to set this up.

Spring MVC - Form Mapping

Probably missing something completely obvious here, but here goes. I'm starting out with Spring MVC. I have a form controller to process inbound requests to /share/edit.html. When I hit this url from my browser, I get the following error:
The requested resource (/inbox/share/share/edit) is not available.
Here is my applicationContext-mvc.xml:
<bean id="publicUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" >
<property name="mappings" >
<value>
/share/edit.html=shareFormController
/share/list.html=shareController
/share/view.html=shareController
/folders.json=foldersController
/studies.json=studiesController
</value>
</property>
</bean>
<bean id="internalPathMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver" />
<bean id="shareFormController" class="com.lifeimage.lila.controller.ShareFormController" />
<bean id="shareController" class="com.lifeimage.lila.controller.ShareController" >
<property name="methodNameResolver" ref="internalPathMethodNameResolver" />
</bean>
and my form Controller:
public class ShareFormController extends SimpleFormController {
public ShareFormController() {
setCommandClass( Share.class );
}
#Override
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)
throws Exception {
//controller impl...
}
}
You should look at your view resolver. Make sure that it is resolving the logical name in your controller as you think it should. Looks like the name it is resolving it to does not exist currently
I think I've resolved this issue. There were two problems:
1) Implementations of SimpleFormController require a form and success view; which I had not configured here. As this is a server method for an AJAX client, I added a Spring-JSON view as follows:
<?xml version="1.0" encoding="UTF-8"?>
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
default-lazy-init="false" default-autowire="no"
default-dependency-check="none">
<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
<property name="jsonErrors">
<list>
<ref bean="statusError" />
<ref bean="modelflagError" />
</list>
</property>
</bean>
<bean name="statusError"
class="org.springframework.web.servlet.view.json.error.HttpStatusError">
<property name="errorCode"><value>311</value></property>
</bean>
<bean name="modelflagError"
class="org.springframework.web.servlet.view.json.error.ModelFlagError">
<property name="name"><value>failure</value></property>
<property name="value"><value>true</value></property>
</bean>
which can be used for all controllers that return JSON.
2) I switched from a SimpleURLHandlerMapping to ControllerClassNameHandlerMapping and relied on Spring naming conventions ( controllerClassName/method.html ), which fixed the routing issue. Might not be a long term solution, but got me through the task.
Did you check your log output? Spring MVC is generally pretty verbose in what it outputs.
Also, the URL you've posted (/inbox/share/share/edit) does not seem to match what you are configuring (/share/edit.html).
#jordan002 when I see all the hoops you had to jump to accomplish your task, I feel obliged to share a very powerful Java MVC framework that requires much less configuration. The framework is called Induction, check out the article Induction vs. Spring MVC, http://www.inductionframework.org/induction-vs-spring-mvc.html

Categories

Resources