Spring Webflow + Spring MVC: Action Bean in Java Annotation - spring

I'm using Spring MVC + Spring Webflow 2.
I would like to define a #Bean for an action-state, but i don't know how to do this in Java Annotation, as i get this error:
Method call: Method execute() cannot be found on
com.myapp.action.GaraAgenziaAction type
here an example of what i want to do: spring-webflow-no-actions-were-executed
My Bean:
import org.springframework.webflow.execution.Action;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
public class GaraAgenziaAction implements Action {
#Override
public Event execute(RequestContext rc) throws Exception {
return new Event(this, "success");
}
}
Flow XML:
<transition on="fail" to="gara-agenzie"/>
<transition on="success" to="gara-conferma"/>
My webAppConfig:
#Bean
public Action GaraAgenziaAction()
{
GaraAgenziaAction garaAgenziaAction = new GaraAgenziaAction();
return garaAgenziaAction;
}
Thank you very much
UPDATE resolved thanks to #Prasad suggestions:
My Bean (added #Component):
import org.springframework.stereotype.Component;
import org.springframework.webflow.execution.Action;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
#Component
public class GaraAgenziaAction implements Action {
#Override
public Event execute(RequestContext rc) throws Exception {
return new Event(this, "success");
}
}
My webAppConfig (changed name of the bean with lowercase):
#Bean
public Action garaAgenziaAction()
{
GaraAgenziaAction beanAction = new GaraAgenziaAction();
return beanAction;
}
Flow XMl configuration (changed bean name to lowercase and pass flowRequestContext as parameter):
<action-state id="action-agenzie">
<evaluate expression="garaAgenziaAction.execute(flowRequestContext)"></evaluate>
<transition on="fail" to="gara-agenzie"/>
<transition on="success" to="gara-conferma"/>
</action-state>
Now it's working fine!

Define the action class in your servlet xml file as:
<!--Class which handles the flow related actions-->
<bean id="garaAgenziaAction" class=" com.myapp.action.GaraAgenziaAction">
</bean>
or annotate it with Component as:
#Component
public class GaraAgenziaAction implements Action{
#Override
public Event execute(RequestContext rc) throws Exception {
return new Event(this, "success");
}
}
In your flow xml access it as:
<action-state id="action-agenzie">
<evaluate expression="garaAgenziaAction.execute(flowRequestContext)"></evaluate>
<transition on="fail" to="gara-agenzie"/>
<transition on="success" to="gara-conferma"/>
</action-state>
For configuration details you can find it in the answer in this link.

Related

Spring Web Flow flowExecutionUrl is empty

I'm making simple order-flow via Spring Web Flow, also i have Spring MVC on my project. I've been doing everything according to guides, but my web-app doesn't react to my flow at all. Spring Web Flow Config:
#Configuration
#ComponentScan(basePackages = "config")
public class WebFlowConfig extends AbstractFlowConfiguration {
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setViewFactoryCreator(mvcViewFactoryCreator())
.setDevelopmentMode(true).build();
}
#Bean
public MvcViewFactoryCreator mvcViewFactoryCreator() {
MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
factoryCreator.setViewResolvers(
Collections.singletonList(this.webMvcConfig.resourceViewResolver()));
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
#Autowired
private DispatcherConfig webMvcConfig;
#Bean
public FlowDefinitionRegistry flowRegistry() {
FlowDefinitionRegistry registry = getFlowDefinitionRegistryBuilder().addFlowLocation("/WEB-INF/flows/order/flowcnf.xml","order").build();
return registry;
}
#Bean
public FlowExecutor flowExecutor() {
return
getFlowExecutorBuilder(flowRegistry()).build();
}
#Bean
public FlowHandlerMapping flowHandlerMapping(){
final FlowHandlerMapping handeler = new FlowHandlerMapping();
handeler.setFlowRegistry(flowRegistry());
handeler.setFlowUrlHandler(defaultFlowUrlHandler());
return handeler;
}
#Bean
public DefaultFlowUrlHandler defaultFlowUrlHandler(){
return new DefaultFlowUrlHandler();
}
#Bean
public FlowHandlerAdapter adapter(){
FlowHandlerAdapter adapter = new FlowHandlerAdapter();
adapter.setFlowUrlHandler(defaultFlowUrlHandler());
adapter.setFlowExecutor(flowExecutor());
return adapter;
}
}
As I said I'm using Spring MVC maybe the problems occurs due to it.
Code snippet below must run "thankCustomer" view-state, but it doesn't.
I get 404 eror if i click the link.
<a class=button href="${flowExecutionUrl}&_eventId=thankCustomer">Замовити!</a>
And the flow code:
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"
start-state="identify">
<var name="order" class="entity.BookOrder"/>
<subflow-state id="identify" subflow="order/custom" >
<output name="user" value="order.custName" />
<transition on="userIsReady" to="buildOrder"/>
</subflow-state>
<subflow-state id="buildOrder" subflow="order/build">
<input name="order" value="order" />
<transition to="takePayment" on="orderBuilt" />
</subflow-state>
<subflow-state id="takePayment" subflow="order/takePayment" >
<input name="order" value="order"/>
<transition on="paymentTaken" to="saveOrder" />
</subflow-state>
<action-state id="saveOrder">
<evaluate expression="userServiceImpl.addOrder(order.custName,order)"/>
<transition to="thankCustomer" />
</action-state>
<view-state id="thankCustomer" view="/WEB-INF/pages/greeting.jsp" >
<transition to="end-point" />
</view-state>
<end-state id="end-point"/>
<global-transitions>
<transition on="cancel" to="end-point" />
</global-transitions>
</flow>
I've tried to put flow id (order) instead of empty flowExecutionUrl, but still the same eror, I'll be grateful for any kinda help.
I needed to set "order" to my FlowHandlerMapping Bean, couse i already had 2 viewResolvers.

Replace Private Method of Spring Bean

i have requirement to replace private method of spring bean, can i achieve through spring replace.
My Code :
Replacer Class :
public class PrivateCarRep extends Car implements MethodReplacer{
#Override
public Object reimplement(Object obj, Method method, Object[] args) throws
Throwable {
// new property of Car.breaks() method.
System.out.println("New privateBreaksIs Done from Shiv");
return obj;
}
}
Car.java
package org.websparrow.beans;
public class Car {
private void privateBreaks() {
System.out.println("Old car break. privateBreaks");
}
}
My Spring Configuration:
<bean id="PrivateCarRep" class="org.websparrow.beans.PrivateCarRep"/>
<bean id="car" class="org.websparrow.beans.Car">
<replaced-method name="privateBreaks" replacer="PrivateCarRep" />
</bean>
Dear All,
i already know that i can't replace private method through spring replacer but is there any workaround for this in spring..
You need to define PrivateCarRep as a bean:
<bean id="privateCarReplacer" class="com.xx.yy.zz.PrivateCarRep" />
<bean id="car" class="org.websparrow.beans.Car">
<replaced-method name="privateBreaks" replacer="privateCarReplacer" />
</bean>
I'm afraid you can't do that,I thing the method should be be protected or public.

Spring WebFlow doesn't use the the implemented validator

Spring webflow does not use the custom validator PatientValidator to validate Patient model while transitioning from selectPatient state to selectDoctor state.
Here is my code
Patient.java
#Data
#Entity
public class Patient implements Serializable {
private static final long serialVersionUID = -5116169782847291743L;
...
}
PatientValidator.java
#Component
public class PatientValidator extends FieldValidator {
public PatientValidator() { }
public void validateSelectPatient(Patient patient, Errors errors) {
System.out.println("PatientValidator . validateSelectPatient");
}
public void validateSelectDoctor(Patient patient, Errors errors) {
System.out.println("PatientValidator . validateSelectDoctor");
}
}
submit-request-flow.xml
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<secured attributes="ROLE_OFFICER" match="any"/>
<on-start>
<evaluate expression="submitRequestFlow.getPatient()" result="flowScope.patient"></evaluate>
</on-start>
<view-state id="selectPatient" view="flows/requests/new/select-patient" model="patient">
<transition on="select" to="selectDoctor"></transition>
</view-state>
<view-state id="selectDoctor" view="flows/requests/new/select-doctor">
<transition on="select" to="selectTestType"></transition>
<transition on="back" to="selectPatient"></transition>
</view-state>
...
<end-state id="finishFlow" view="externalRedirect:#{uri.get('requests')}">
<output name="success" value="'Request has been added successfully'"/>
</end-state>
<end-state id="cancelFlow" view="externalRedirect:#{uri.get('requests')}">
</end-state>
<global-transitions>
<transition on="cancel" to="cancelFlow" history="discard" bind="false" validate="false"></transition>
</global-transitions>
</flow>
Even if I use the validation method inside Patient.java, the webflow uses it.
#Data
#Entity
public class Patient implements Serializable {
private static final long serialVersionUID = -5116169782847291743L;
...
public void validateSelectPatient(Errors errors) {
errors.reject("NoResultFound");
}
}
I have to use the custom validation rather than the model one, it works just the first time, but I guess after I rebooted spring boot project it doesn't work anymore.
Update #1
I am using
Spring boot 1.5.6.RELEASE
Spring WebFlow 2.4.5.RELEASE
Thymeleaf 3.0.7.RELEASE
Thymeleaf SpringSecurity4 3.0.2.RELEASE
I guess issue is related how spring DevTools works, here is a workaround I have done for another issue here SpelEvaluationException Method cannot be found.

Access session scoped variable in spring interceptor

How can i access session scoped variable in spring interceptor?
Session scoped class:
#Component
#Scope("session")
public class User {
}
Controller:
#Controller
#RequestMapping("/restricted")
#Scope("request")
public class RestrictedController {
#Autowired
private User user;
}
Dispatcher servlet:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/restricted/*"/>
<bean class="com.interceptors.RestrictedInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
Interceptor class:
public class RestrictedInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
}
}
In prehandle i want to check if user is logged in (some other checks as well), how can i access session scoped user variable here? Autowiring user in Interceptor class throws exception.
You should be able to access your session-scoped user using the following code:
request.getSession().getAttribute("scopedTarget.user");
See related post here and org.springframework.aop.scope.ScopedProxyUtils class.

How to directly display a property value defined via PropertySourcesPlaceholderConfigurer in a jsp (Spring framework)?

I have the following configuration in Spring application context.
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="props">
<list>
<value>file://${user.home}/myConfig.properties</value>
</list>
</property>
</bean>
let's say I want to display a value (e.g : app.url.secret) defined as a property in the myConfig.properties file, directly in a jsp. How can I achieve that ?
thanks in advance for your help
You will have to get it to your model in some way:
One approach will be to use a PropertyHolder this way:
#Component
public class PropertyHolder {
#Value("${myprop}")
private String myProperty;
//getters and setters..
}
In your controller:
#Controller
public class MyController {
#Autowired private PropertyHolder propertyHolder;
#ModelAttribute
public void setModelAttributes(Model model) {
model.put("myprops", propertyHolder);
}
....rest of your controller..
}
then you have access to myprops in your jsp - myprops.myProperty
Firstly populate your model with the property value on your controller, then return a view that resolves to your JSP
You can use #Value annotation to inject the property to your controller
#Controller
public class MyController {
#Value("${app.url.secret}") private String urlSecret;
#RequestMapping("/hello")
public String hello(Model model) {
model.addAttribute("urlSecret", urlSecret);
// assuming this will resolve to hello.jsp
return "hello";
}
}
Then on your hello.jsp
<%# page ... %>
<html>
...
The secret url is: ${urlSecret}

Resources