Struts 2 single jsp page to execute multiple different methods - struts2

I am migrating from struts 1 to struts 2 framework. Based on struts 1 framework parameter=method attribute, I am able to execute different methods using the same jsp page by adding a hidden field "method".
How do I achieve the same in struts 2?
My Action class:
public class MyAction extends ActionSupport {
public String methodA() {
return "a";
}
public String methodB() {
return "b";
}
}
My JSP page
<s:form action="MyAction">
<s:select label="Method Name"
name="method"
headerKey="-1" headerValue="Select Method"
list="#{'01':'A', '02':'B', [...]}"
value="selectedMethod"
required="true"
/>
<s:submit type="button" name="submit" />
</s:form>

You could achieve that by changing the "action" url before submitting.
Check out Wildcard Method and Dynamic Method Invocation here
Though, the dynamic Method Invocation can be considered a Security Vulnerability

Related

JSF2.2 Multiple field validation message not appearing.. the message is associated to a component [duplicate]

JSF 2.0 only allows you to validate the input on one field, like check to see if it's a certain length. It doesn't allow you to have a form that says, "enter city and state, or enter just a zip code."
How have you gotten around this? I'm only interested in answers that involve the validation phase of JSF. I'm not interested in putting validation logic in Managed Beans.
The easiest custom approach I've seen and used as far is to create a <h:inputHidden> field with a <f:validator> wherein you reference all involved components as <f:attribute>. If you declare it before the to-be-validated components, then you can obtain the submitted values inside the validator by UIInput#getSubmittedValue().
E.g.
<h:form>
<h:inputHidden id="foo" value="true">
<f:validator validatorId="fooValidator" />
<f:attribute name="input1" value="#{input1}" />
<f:attribute name="input2" value="#{input2}" />
<f:attribute name="input3" value="#{input3}" />
</h:inputHidden>
<h:inputText binding="#{input1}" value="#{bean.input1}" />
<h:inputText binding="#{input2}" value="#{bean.input2}" />
<h:inputText binding="#{input3}" value="#{bean.input3}" />
<h:commandButton value="submit" action="#{bean.submit}" />
<h:message for="foo" />
</h:form>
(please note the value="true" on the hidden input; the actual value actually doesn't matter, but keep in mind that the validator won't necessarily be fired when it's null or empty, depending on the JSF version and configuration)
with
#FacesValidator(value="fooValidator")
public class FooValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
UIInput input1 = (UIInput) component.getAttributes().get("input1");
UIInput input2 = (UIInput) component.getAttributes().get("input2");
UIInput input3 = (UIInput) component.getAttributes().get("input3");
// ...
Object value1 = input1.getSubmittedValue();
Object value2 = input2.getSubmittedValue();
Object value3 = input3.getSubmittedValue();
// ...
}
}
If you declare the <h:inputHidden> after the to-be-validated components, then the values of the involved components are already converted and validated and you should obtain them by UIInput#getValue() or maybe UIInput#getLocalValue() (in case the UIInput isn't isValid()) instead.
See also:
Validator for multiple fields (JSF 1.2 targeted)
Alternatively, you can use 3rd party tags/components for that. RichFaces for example has a <rich:graphValidator> tag for this, Seam3 has a <s:validateForm> for this, and OmniFaces has several standard <o:validateXxx> components for this which are all showcased here. OmniFaces uses a component based approach whereby the job is done in UIComponent#processValidators(). It also allows customizing it in such way so that the above can be achieved as below:
<h:form>
<o:validateMultiple id="foo" components="input1 input2 input3" validator="#{fooValidator}" />
<h:inputText id="input1" value="#{bean.input1}" />
<h:inputText id="input2" value="#{bean.input2}" />
<h:inputText id="input3" value="#{bean.input3}" />
<h:commandButton value="submit" action="#{bean.submit}" />
<h:message for="foo" />
</h:form>
with
#ManagedBean
#RequestScoped
public class FooValidator implements MultiFieldValidator {
#Override
public boolean validateValues(FacesContext context, List<UIInput> components, List<Object> values) {
// ...
}
}
The only difference is that it returns a boolean and that the message should be specified as message attribute in <o:validateMultiple>.
Apache ExtVal was not mentioned here.
There are some cross validations in it (among other validations which might be useful):
https://cwiki.apache.org/confluence/display/EXTVAL/Property+Validation+Usage#PropertyValidationUsage-CrossValidation

Struts 2 display tags

I have a JSP which has below tags the data in resultsList fed in some action and forwarded to below jsp here I would like to get the data back into the other action based on the checkbox selection. Please help, can do using Struts1 but don't like to turn back to Struts1 since started using Struts2.
<display:table class="displaytag" id="row" style="font-size:1.4em;" name="resultsList" requestURI="/SomePath.action">
<display:column property="businessType" title="Business Type"></display:column>
<display:column property="structure" title="Structure"></display:column>
<display:column property="tradeSubType" title="Trade Sub Type"></display:column>
<display:column property="businessGroup" title="Business Group"></display:column>
<display:column title="Select To Copy" align="center">
<s:checkbox name="selectToCopy" fieldValue="false" value="false" label="Check Me To Download"></s:checkbox>
</display:column>
</display:table>
The data will be fetched in one action and forwarded to the jsp where jsp contains above display tag and now I need to submit the form and action should receive the checked information to process further. Any help here is really appreciated, I can do it using Struts1 no doubt but would like to continue in Struts2.
I'm guessing your action class sends some domain objects from this type:
public class MyData {
private Integer id;
private String businessType;
//other params
//getter/setters
}
And your action class, that ist invoked before accessing the displaytag jsp page has a list of objects form type MyData:
public class MyDisplayTagAction extends ActionSupport {
private List<MyData> myDataList;
//other params
//getter/setter
public String execute() {
myDataList = getMyDataListFromSomewhere();
return SUCCESS;
}
}
The JSP should contain a form and a submit button. Moreover you have to define every data you want to send back as a field in that form. If the user is not allowed to change them, use hidden fields. The #attr.row.id access printing that id to the value. #attr is from ognl to access the variable row defined from displaytag. (For more info: Struts OGNL)
<s:form action="myStrutsPostAction" method="post">
<display:table name="myDataList" uid="row">
<display:column>
<s:checkbox name="resultsList[%{#attr.row_rowNum - 1}].selectToCopy" id="check%{#attr.row_rowNum - 1}" value="%{#attr.row.selectToCopy}"/>
</display:column>
<display:column>
<input type="hidden" name="resultsList[<s:property value='%{#attr.row_rowNum - 1}'/>]" value="<s:property value='%{#attr.row.businessType}' />"/>
<s:property value="%{#attr.row.businessType}"/>
</display:column
</display:table>
<s:submit>
</s:form>
The post action class (the one that takes the form request) should contain a list, that was defined in the <s:form> and struts will set only the the data into this list.
public class MyPostAction extends ActionSupport {
private List<MyData> resultsList = new ArrayList<>();
//getter/setter
}

Input text returning null value

This might be simple problem, but I am not able to figure it out.
Here is my xhtml page:
*update p tag here, I am using primefaces*
<h:outputLabel for="Number" value="Number(100-800):" />
<h:inputText id="number" name="number_Name" value="#{validationView.number}" label="Number">
<f:validateDoubleRange minimum="100" maximum="800" />
</h:inputText>
<p:commandButton value="S-ubmit" name="submit" actionListener="#{userBean1.method1}" ajax="false" icon="ui-icon-check" validateClient="true"/>
This is my managed bean
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.primefaces.context.RequestContext;
#ManagedBean(name="userBean1")
#SessionScoped
public class UserBean1
{
public void method(){
String value = FacesContext.getCurrentInstance().
getExternalContext().getRequestParameterMap().get("number_Name");
System.out.println("Value: "+value);
}
public void method1(ActionEvent event) {
String param = (String) event.getComponent().getAttributes().get("number_Name");
System.out.println("Param: "+param);
}
}
I tried both methods and in both cases it is printing null output. I imported el-impl-2,2.jar into my build path. I am using primefaces 5.1 and Tomcat7
First, there is no attribute called name in h:inputText, if you really need to use that attribute, please refer to that question for more details: How to specify name attribute in h:inputText?
So I will assume your h:inputText looks something like this:
<h:inputText id="number" value="#{validationView.number}" label="Number">
<f:validateDoubleRange minimum="100" maximum="800" />
</h:inputText>
Second, in the externalContext().getRequestParameterMap().get(key) the key refers to the request parameters names included in the current request, which corresponds to the client ID (because name is autogenerated by JSF based on the client ID), so if for example your h:inputText is inside a form whose id= "form" then your client ID will be "form:number", More about When and how is clientID generated in JSF?
You can use your first method like this:
public void method(){
String value = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("form:number");
System.out.println("Value: "+value);
}
In case you only know the component id of your h:inputText and not it's client ID please refer to: Find component by ID in JSF
Finnaly, I think that the best way is to use the following method which make you benefit from the ActionEvent:
public void method(ActionEvent event) {
String param = (String) ((UIInput) event.getComponent().findComponent("form:number")).getValue();
System.out.println("Param: "+param);
}
NB: please note that event.getComponent() gets the component that triggered the event which is p:commandButton (in your case) and not the h:inputText

How can I avoid a language change in liferay to trigger the last actionReques

When changing languages from the language portlet, the user is redirected to the last URL. If the URL corresponds to an actionRequest, that action is triggered a second time.
I tried with the following simple code, with the classic theme, in liferay 6.1 GA2
view.jsp:
<%# taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<portlet:defineObjects />
<portlet:actionURL name="myProcessAction" var="myProcessActionURL" />
my process action
<form action="<%= myProcessActionURL %>" method="post">
<input type="submit" />
</form>
testportlet.java:
public class TestPortlet extends MVCPortlet {
public void myProcessAction(ActionRequest actionRequest,
ActionResponse actionResponse) throws IOException, PortletException {
_log.info("processing action");
}
private static Log _log = LogFactoryUtil.getLog("TestPortlet");
}
I add my test portlet to a new page, as well as the language portlet.
Submit the form -> log shows "processing action"
switch languages -> log shows "processing action" again !
Best regards,
Alain
You can specify where the page is redirected by including a "redirect" parameter. For example:
<input type="hidden" name="<portlet:namespace />redirect" value="/" />
The MVCPortlet class will automatically see this parameter and redirect to it if the request is successful.

ASP.NET MVC with Spring.NET and ModelBinder

I'm working on a demo that makes use of Spring.NET IoC capability in ASP.NET MVC . It's kind of like the MyBlog application presented on pair programming video tutorial on www.asp.net site. I've completed the same demo using Microsoft's Unity framework and now want to try out the Spring container.
To that end I've implemented a simple IControllerFactory that first creates the Spring object factory like that:
IObjectFactory factory;
(....)
factory = new XmlObjectFactory(new FileSystemResource(application.Server.MapPath("objects.xml")))
and next it gets the controller from that factory like that:
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) {
IController result = context.GetObject(controllerName) as IController;
return result;
}
(error handling stripped for simplification purposes).
Now somewhere in my HomeController I have this kind of action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddEntry([Bind] BlogEntry entry, int id) {
entry.EntryDate = DateTime.Now;
....
And here's the part of AddEntry.aspx view that defines the editors for entry parameter (really basic stuff):
<form method="post" action="/Home/AddEntry/<%= ViewData["id"] %>">
<table>
<tr>
<td><label for="Title">Title</label></td>
<td><input name="entry.Title" type="text"/></td>
</tr>
<tr>
<td><label for="Text">Content</label></td>
<td><input name="entry.Text" type="text"/></td>
</tr>
</table>
<br />
<input type="submit" value="Add entry" />
<input type="button" value="Cancel" onclick="history.back(-1);" />
</form>
Now here's the deal:
When I'm using the Unity IoC it works like a charm. "entry" parameter gets deserialized from my form like it should and the line
entry.EntryDate = DateTime.Now;
completes without problems.
However when I switch to Spring.NET object factory (like described above) things begin to go nuts. First of all the parameter "entry" turns null so an exception is thrown.
To track the possible problem on my end I've implemented a sort of custom IModelBinder that looks like that:
public class BlogEntryBinder : IModelBinder {
public ModelBinderResult BindModel(ModelBindingContext bindingContext) {
ModelBinderResult result = ModelBinders.DefaultBinder.BindModel(bindingContext);
return result;
}
}
When I come here using the Unity framework and drill down from bindingContext to HttpRequest I see that the Request.HttpMethod is "POST" and Request.Form is properly filled. When I do the same using Spring.NET the method is "GET" and Request.Form is empty.
When however I step to my controller action (AddEntry) and drill down to the Request in both situations I see that the Request.HttpMethod and Request.Form have their proper values.
Now the question is how do I fix the version with Spring.NET so that it works just like the one that uses Unity framework?
I've found the answer!
My object definition looked like that:
<!-- Controlers -->
<object name="Home" type="MyBlog.Controllers.HomeController">
<property name="BlogService" ref="BlogService" />
<property name="BlogEntryService" ref="BlogEntryService" />
<property name="BlogEntryCommentService" ref="BlogEntryCommentService" />
</object>
Nevermind the properties being set what it actually does is it returns the same instance every time I ask for this object using
IController result = context.GetObject(controllerName) as IController;
So when I've changed the definition to
<!-- Controlers -->
<object name="Home" type="MyBlog.Controllers.HomeController" singleton="false">
<property name="BlogService" ref="BlogService" />
<property name="BlogEntryService" ref="BlogEntryService" />
<property name="BlogEntryCommentService" ref="BlogEntryCommentService" />
</object>
everything started work just fine.
Best regards,
Matthias.
just an additional note for clarifying this behavior: Controllers are treated as prototypes by the ASP.NET MVC framework, but Spring defaults to singleton mode. Therefore you need to explicitly mark your object as non-singleton in the container configuration. The upcoming Spring MVC integration module will take care of this, so you won't run into this then.
hth,
Erich

Resources