I have a Action class with few fields (String, int etc) + instance of User class (userBean) inside it. If I want to validate field values I can do it using validation framework, but if I want to validate "userBean.username" from User class how can I do that using validation framework?
Tried below but did not work
<field name="userBean.username">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message key="errors.required" />
</field-validator>
</field>
Thanks in advance
You need to validate the inputs of a form, you can't use it this way. The validation framework kicks in before the action treats the request (see interceptors), that's why you can't do what you're doing. So regarding your question, you need to put the actual field name which matches your username and then set its value to your UserBean instance.
If you need more infos, just check the official doc.
Related
For instance, I have a field to enter telephone number and i want it to be validated. I.e. check if the value entered is numeric and check if the entered value is having 10 digits.
I achieved this by creating a validation.xml.
But my question is How can i use the same set of validation rules(the same file) for another field? Is that possible in Struts 2?
Not sure if this is what you are looking for:
Create a new file called validators.xml in WEB-INF/classes and define the new validator.
<validator name="newvalidator" class="FQCN"/>
Create a class which extends FieldValidatorSupport to implement your own validation logic.
Use the new validator in validation xml files
<field-validator type="newvalidator">
I have a JSP page where am printing the arraylist content via an iterator
<s:iterator var="BeanList" value="BeanList">
<option value='<s:property value="#BeanList.simpleID"/>'>
<s:property value="#BeanList.simpleText" />
</option>
</s:iterator>
Every time the user selects an option, the form submits to the action handling. I want to be able to take the value of the clicked option, and when the page is reloaded after the submit, the same value persists in the select drop down.
Any help will be greatly apprecaited,
You are using HTML Select Tag, with values populated from Struts2 Property Tag.
No JSTL is involved.
But believe me, you can avoid this using the Struts2 Select Tag directly.
Official documentation: http://struts.apache.org/release/2.3.x/docs/select.html
In Action
#Getter #Setter List<String> allCities;
#Getter #Setter String selectedCity;
In JSP:
<s:select list="allCities"
name="selectedCity" />
Faster and cleaner than iterating manually :)
Eventually you can add an optional header value:
<s:select list="allCities"
name="selectedCity"
headerKey="-1"
headerValue="Select a City" />
For that you need to declare a variable with select box name in Action class, and put setter and getter for that. And then, when you are submitting the form, the name matches and it automatically populate in Action class.
When retrieving the data set value to same variable.Then it will populate automatically by using name.
This will happen by using params interceptor internally.
I want to assign the value from field Description to a hidden field test.
But the problem is the "Description" contains sequence of words and the following code is assigning only first word to "test"
<s:hidden value=<s:property value="Description" /> name="test">
I am kind of new to struts. Can someone please help.
Also it would be nice if i get to know good tutorial links of struts2.
If this is a property in your action class you need not to use <s:property value="Description" /> as the Description will be available at the top of value stack and you can use OGNL to fetch the value from value-stack.This is what you need to do
<s:hidden value="%{description}" name="test" />
Please make sure the value in hidden filed should be similar to the name of property in your action class as it will be resolved to either the getter and setter in your action class or the public property defined in your action.
So this means value="%{description}" will be converted by OGNL like getDescription() and will try to find the getter in your action class to fetch the property value.
<s:hidden value="%{description}" name="test" />
Form field is not automatically getting populated for below scenario
public class EmployeeAction extends ActionSupport implements ModelDriven{
private Employee employee=new Employee();
public Object getModel() {
return employee;
}
public String execute() throws Exception {
employee=employeeService.findById(employee.getId());
return super.execute();
}
}
the problem is new employee object but form is expecting old object reference , so manual mapping is working fine,
public String execute() throws Exception {
BeanUtils.copyProperties(employee,employeeService.findById(employee.getId()));
return super.execute();
}
how to avoid this object(new/old) reference problem
Employee.jsp
<s:form action="saveemployee" method="post">
<s:hidden name="id"></s:hidden>
<s:textfield name="name" label="Name" />
<s:textfield name="age" label="Age"></s:textfield>
<s:radio name="gender" label="Gender" list="%{staticMasterMap.gender}" listKey="key" listValue="value" ></s:radio>
<s:label value="DOB"></s:label><fw:datepicker name="dob" id="dob" changeMonth="true" changeYear="true" format="dd/mm/yy" yearRange="1900:2010"></fw:datepicker>
<s:textarea name="address" label="Address"></s:textarea>
<s:submit label="Save"></s:submit>
<s:reset label="Reset"></s:reset>
</s:form>
Struts.xml
<package name="fw" extends="struts-default" namespace="/">
<action name="saveemployee" class="com.example.employee.action.EmployeeAction"
method="save">
<result name="input" type="tiles">employee</result>
<result name="success" type="tiles">employee</result>
</action>
<action name="findemployee" class="com.example.employee.action.EmployeeAction" method="findById">
<result name="success" type="tiles">employee</result>
<result name="input" type="tiles">employee</result>
</action>
</package>
I have not much worked with Struts2 Model Driven Interface and can not recommend what best can be done in your case, but if i am right this is one of the pitfalls of using the Model Driven Interface.
In your case by the time the execute() method has been invoked S2 already has obtained a reference to your Model object which it will use for this particular request cycle. This means you're changing the reference inside your execute method using
employee=employeeService.findById(9l);
but still the framework has reference to the old model object. Since S2 gets the reference using the getter method it has no information what you are doing inside execute method and which is the cause of your data inconsistency.
Honestly i am not sure about any solution for this use-case and will go for a simple Object backed property approach.
Hope some one can provide a workaround if my inputs are correct.
I think the problem is simpler. By default, Struts 2 actions are instanced in each request (also written as having a scope of a request).
When you find a certain Employee an instance of EmployeeAction is created and used to populate the form.
When you press the "Save" button, a new instance of EmployeeAction is created with a new (empty) Employee instance.
You could verify if this is the case by having a constructor log something or using a debugger.
Solving this could be done by saving information to the Session (the employee id, for example) and verifying this data to create a new Employee instead.
Other option is to change the ObjectFactory of Struts 2 to something like Spring.
References: I've used Struts2 with and without Spring and tried to find some official reference. Struts 2 documentation is not clear about the instance creation in the request cycle but the documentation for the Spring plugin of Struts 2 says
Spring 2's bean scope feature can be used to scope an Action instance
to the session, application, or a custom scope, providing advanced
customization above the default per-request scoping.
In struts2 we use
<action name="anAction">
<result name="success">xx.jsp</result>
</action>
to define action, and use s:url to generate a link to the action
<s:url action="anAction"></s:url>
The above s:url will output "/anAction.do".
I wonder if it's possible to let s:url generate a default URL parameter (i.e. /anAction.do?p=xxx for all links), without modifying the existing s:url tags (there are many and they are scattered). The goal is to let the parameter appear in the link for SEO purpose.
Available options can be: changing any action config, changing any struts config, even rewrite the s:url generation class.
Edit: I found that adding this to struts.xml
<constant name="struts.url.includeParams" value="get" />
partially solves my problem (as long as the initial page has ?p=xxx, all subsequent links will have it). The short-comings are obvious: the parameter will not follow a redirect action. I am still searching for more sophisticated solution.
I did figure out how this can be done. The steps are:
1) create a class which implements org.apache.struts2.components.UrlRenderer
2) register that class with struts object factory and it will be injected as necessary
Details? Ok.
1) For example, a subclass of ServletUrlRender might look like this:
package com.example;
import java.util.Map;
import org.apache.struts2.components.ServletUrlRenderer;
import org.apache.struts2.components.UrlProvider;
public class ParameterInjectingUrlRenderer extends ServletUrlRenderer {
#Override
protected void mergeRequestParameters(String value, Map<String, Object> parameters, Map<String, Object> contextParameters) {
super.mergeRequestParameters(value, parameters, contextParameters);
parameters.put("myParameter", "secretvalue");
}
}
2) In struts.xml, set this class as the renderer implementation, with a line like this:
<constant name="struts.urlRenderer" value="parameterInjectingUrlRenderer" />
(In this example I'm using a Spring object factory, and value references a spring bean id. If you are not, I believe you put the fully-qualified class name).
That's it!
Global Search and replace (All IDE's should have this feature)
<s:url action="anAction"></s:url>
With
<s:url action="anAction"><s:param name="p" value="'xxx'"/></s:url>
Now every "anAction" will have a parameter p with value xxx.
It generally a good idea to specify the namespace.
<s:url namespace="/" action="anAction"><s:param name="p" value="'xxx'"/></s:url>