I am pretty familiar with Struts 2... Since 3 days I've been stuck in a very strange problem.
I have many attributes in my action class; some are Integers, the others are Strings. I know I have created both of the getters/setters for all my attributes
showcase extends struts-default and json-default because i need the class to render a json table i am using the struts2-jquery gridtag....none of my attributes are being printed exept sord,sdix,page.. those defined by the tag
My Action Class
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.convention.annotation.ParentPackage;
import amz.votrerepas.dao.CategorieDao;
import amz.votrerepas.dao.CategorieDaoImplementation;
import amz.votrerepas.dao.ProduitDao;
import amz.votrerepas.dao.ProduitDaoImplementation;
import amz.votrerepas.models.Produit;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
#ParentPackage(value = "showcase")
public class ProduitAction extends ActionSupport implements Preparable{
private static final long serialVersionUID = 947577563329037436L;
private List<Produit> produits;
private String searchOper = "asc"; // Search operator
private String sord; // sorting order - asc or desc
private String sidx; // get index row - i.e. user click to sort.
private String searchField; // Search Field
private String searchString; // The Search String
private String oper;
private Integer rows = 0;
private Integer page = 0;
private Integer total = 0;
private Integer records;
private String myeditOptions;
#Override
public void prepare() throws Exception {
CategorieDao catdao = new CategorieDaoImplementation();
Map<Long, String> listEditOptions = catdao.getAllCategories();
List<String> arraywithresulttupels = new ArrayList<String>();
for (Long key : listEditOptions.keySet()) {
arraywithresulttupels.add(""+key+":"+listEditOptions.get(key));
}
Collections.sort(arraywithresulttupels);
myeditOptions = "{value:'" + StringUtils.join(arraywithresulttupels, ";")
+ "'}";
}
#Override
public String execute() throws Exception {
ProduitDao dao = new ProduitDaoImplementation();
produits = dao.getallProducts();
return SUCCESS;
}
public String getJSON() throws Exception {
return execute();
}
public List<Produit> getProduits() {
return produits;
}
public void setProduits(List<Produit> produits) {
this.produits = produits;
}
public String getSearchOper() {
return searchOper;
}
public void setSearchOper(String searchOper) {
this.searchOper = searchOper;
}
public String getSord() {
return sord;
}
public void setSord(String sord) {
this.sord = sord;
}
public String getSidx() {
return sidx;
}
public void setSidx(String sidx) {
this.sidx = sidx;
}
public String getSearchField() {
return searchField;
}
public void setSearchField(String searchField) {
this.searchField = searchField;
}
public String getSearchString() {
return searchString;
}
public void setSearchString(String searchString) {
this.searchString = searchString;
}
public String getOper() {
return oper;
}
public void setOper(String oper) {
this.oper = oper;
}
public Integer getRows() {
return rows;
}
public void setRows(Integer rows) {
this.rows = rows;
}
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
public Integer getRecords() {
return records;
}
public void setRecords(Integer records) {
this.records = records;
}
public String getMyeditOptions() {
return myeditOptions;
}
public void setMyeditOptions(String myeditOptions) {
this.myeditOptions = myeditOptions;
}
}
SomeWhere in My JSP page
<s:property value="%{myeditOptions}"/>
<s:property value="%{page}"/>
Struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.devMode" value="false" />
<!-- ******************************** Comptes Actions ******************************** -->
<package name="default" extends="struts-default" namespace="/auth">
<action name="authenticate" class="amz.votrerepas.actions.Authenticate" method="execute">
<result name="success" type="redirectAction">
<param name="actionName">indexProduits</param>
<param name="namespace">/products</param>
</result>
<result name="error">/pages/welcome.jsp</result>
</action>
</package>
<!-- ******************************** Produits Actions ******************************** -->
<package name="categories" extends="struts-default" namespace="/products">
<action name="indexProduits" class="amz.votrerepas.actions.CategorieAction" method="execute">
<result name="success">/pages/admin/products.jsp</result>
</action>
<action name="edit-categorie-grid-entry" class="amz.votrerepas.actions.CategorieEditAction" method="execute">
<result name="success"> /pages/admin/products.jsp </result>
<result name="input"> /pages/admin/products.jsp </result>
</action>
<action name="edit-produit-grid-entry" class="amz.votrerepas.actions.ProduitEditAction" method="execute">
<result name="success"> /pages/admin/products.jsp </result>
<result name="input"> /pages/admin/products.jsp </result>
</action>
</package>
<!-- ******************************** Json Actions ******************************** -->
<package name="showcase" extends="struts-default,json-default" namespace="/jquery">
<action name="jsontableCats" class="amz.votrerepas.actions.CategorieAction" method="getJSON">
<result name="success" type="json" />
</action>
<action name="jsontableProds" class="amz.votrerepas.actions.ProduitAction" method="getJSON">
<result name="success" type="json" />
</action>
</package>
</struts>
My Lib Folder
antlr-2.7.6
antlr-2.7.7
asm-3.3.1
asm-3.3
asm-commons-3.3
asm-tree-3.3
cglib-2.2.2
codegen-0.5.9
commonj.sdo-2.1.1.v201112051852
commons-collections-3.1
commons-fileupload-1.2.2
commons-io-2.0.1
commons-lang-2.6
commons-lang3-3.1
dom4j-1.6.1
ecj-3.7.2
eclipselink-2.4.0
freemarker-2.3.19
guava-13.0.1
hibernate3
hibernate-commons-annotations-4.0.1.Final
hibernate-core-4.1.7.Final
hibernate-entitymanager-4.1.7.Final
hibernate-jpa-2.0-api-1.0.0.Final
hibernate-validator-4.3.0.Final
javassist-3.11.0.GA
javassist-3.12.0.GA
javassist-3.15.0-GA
javax.inject-1
javax.persistence-2.0.4.v201112161009
jboss-logging-3.1.0.GA
jboss-transaction-api_1.1_spec-1.0.0.Final
joda-time-1.6
json-lib-2.3-jdk15
jsr305-1.3.9
jta-1.1
log4j-1.2.16
mysema-commons-lang-0.2.4
mysql-connector-java-5.1.25-bin
ognl-3.0.6
querydsl-apt-3.1.1
querydsl-codegen-3.1.1
querydsl-core-3.1.1
querydsl-jpa-3.1.1
querydsl-jpa-3.1.1-apt
querydsl-jpa-3.1.1-javadoc
querydsl-sql-3.1.1
slf4j-api-1.6.1
slf4j-log4j12-1.6.1
struts2-convention-plugin-2.3.14
struts2-core-2.3.14
struts2-jquery-grid-plugin-3.5.1
struts2-jquery-plugin-3.5.1
struts2-json-plugin-2.3.14
validation-api-1.0.0.GA
xwork-core-2.3.14
The Value of page is shown but the value of myeditOptions is not.....
Pleeeease help
#Lord-zed I see that you populate myEditOptions only on prepare() method. It is not populated again when the "execute" action is hit. So either you must populate it again in execute() or put a hidden field in the jsp of the prepare action to post it back to the "execute" action. I would propose to repopulate it in the execute().
There is no need to typecast the getters and setters,
You should create different file of getters and setters and DAO too.
Related
I'm new to Struts framework. So seeking some online tutorials and tried to develop a very basic application. Before using interceptors am able to access username and password values in action class but after involving interceptors am getting username and password as null in action class execute method. How can i get the values of username and password inside action class?
login.jsp
<s:form action="login.action">
<s:actionerror cssStyle="color:red"/>
<s:textfield name="username" label="Username"/>
<s:password name="password" label="Password"/>
<s:submit value="Go"/>
</s:form>
Interceptor class
public class MyInterceptors extends AbstractInterceptor {
/**
*
*/
private static final long serialVersionUID = 1L;
public String intercept(ActionInvocation invocation)throws Exception{
/* let us do some pre-processing */
String output = "Pre-Processing";
System.out.println(output);
/* let us call action or next interceptor */
String result = invocation.invoke();
/* let us do some post-processing */
output = "Post-Processing";
System.out.println(output);
return result;
}
}
Action class
public class LoginAction extends ActionSupport {
/**
*
*/
private static final long serialVersionUID = 1L;
private String username;
private String password;
public String execute() {
System.out.println("Action Result.."+getUsername());
return "success";
}
//getters and setters
}
struts.xml
.....
<interceptors>
<interceptor name="myinterceptor"
class="com.techm.interceptors.MyInterceptors" />
</interceptors>
<action name="login" class="com.techm.actions.LoginAction">
<interceptor-ref name="myinterceptor"></interceptor-ref>
<result name="success">Success.jsp</result>
<result name="error">Login.jsp</result>
</action>
.....
Result on execution in console is :
Pre-Processing
Action Result..null
Post-Processing
In the action config you have overridden the interceptors configuration. Struts by default is configured to use a default stack of interceptors even if you don't use any interceptors in the action config. By overriding interceptors you made a mistake. You should add a defaultStack in your specific action config.
<action name="login" class="com.techm.actions.LoginAction">
<interceptor-ref name="myinterceptor">
<interceptor-ref name="defaultStack"/>
<result name="success">Success.jsp</result>
<result name="error">Login.jsp</result>
</action>
I've created a Struts2 project in which I used XML based validation. Model class RegistrationForm is shown below
package com.projects;
import com.opensymphony.xwork2.ActionSupport;
public class RegistrationForm implements Serializable{
private static final long serialVersionUID = 1L;
private String fname;
private String lname;
private int numbr;
public int getNumbr() {
return numbr;
}
public void setNumbr(int numbr) {
this.numbr = numbr;
}
public String getFname() {
return fname;
}
public void setFname(String fname) {
this.fname = fname;
}
public String getLname() {
return lname;
}
public void setLname(String lname) {
this.lname = lname;
}
}
RegistrationFormAction.Java
package com.projects;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class RegistrationFormAction extends ActionSupport implements ModelDriven<RegistrationForm> {
private RegistrationForm registrationForm;
public RegistrationForm getRegistrationForm() {
return registrationForm;
}
public void setRegistrationForm(RegistrationForm registrationForm) {
this.registrationForm = registrationForm;
}
public RegistrationForm getModel(){
registrationForm=new RegistrationForm();
return registrationForm;
}
public String execute(){
return "success";
}
}
struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.devMode" value="true" />
<package name="dd" extends="struts-default">
<interceptors>
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception" />
<interceptor-ref name="alias" />
<interceptor-ref name="servletConfig" />
<interceptor-ref name="prepare" />
<interceptor-ref name="i18n" />
<interceptor-ref name="chain" />
<interceptor-ref name="debugging" />
<interceptor-ref name="profiling" />
<interceptor-ref name="scopedModelDriven" />
<interceptor-ref name="modelDriven" />
<interceptor-ref name="params"/>
<interceptor-ref name="validation"/>
<interceptor-ref name="fileUpload" />
<interceptor-ref name="checkbox" />
<interceptor-ref name="staticParams" />
<interceptor-ref name="conversionError" />
<interceptor-ref name="workflow"/>
</interceptor-stack>
</interceptors>
<action name="submitForm" class="com.projects.RegistrationFormAction">
<interceptor-ref name="defaultStack" />
<result name="success">/WelcomePage.jsp</result>
<result name="input">/RegistrationForm.jsp</result>
</action>
</package>
</struts>
RegistrationFormAction-validation.xml
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<field name="registrationform">
<field-validator type="visitor">
<param name="appendPrefix">false</param>
<message/>
</field-validator>
</field>
</validators>
RegistrationForm-validation.xml
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<field name="fname">
<field-validator type="requiredstring">
<message>First Name can't be blank</message>
</field-validator>
</field>
<field name="lname">
<field-validator type="requiredstring">
<message>Last Name can't be blank</message>
</field-validator>
</field>
<field name="numbr">
<field-validator type="int">
<param name="min">1</param>
<param name="max">10</param>
<message>Number between 1 to 10</message>
</field-validator>
</field>
</validators>
but validation is not working.
There are a lot of things goin' on here! I'll post them in order of appearance in the question:
Never make a POJO extends ActionSupport:
public class RegistrationForm extends ActionSupport {
must become
public class RegistrationForm implements Serializable {
Better returning SUCCESS than "success" to prevent typos (but ok this is secondary);
The intercetpor stack customization has four problems:
you are overriding the existing basicStack, this risks to violate the POLA, especially if other people will work on this project; it's better to use a custom name instead, eg. myStack;
you are using only three interceptors, and this is suspicious; while many of the default interceptors can be dropped, many others instead should be always kept, especially with validation involved, eg. ConversionError Interceptor, or Workflow Interceptor, etc. Read how the whole thing works. As a rule, you should remove an Interceptor only when you know exactly what it does and you are absolutely sure you don't (and won't) need it.
When using ModelDriven (that is usually not recommended, because basically useless and source of problems when not experts with it), you need to put the ModelDriven Interceptor before the Parameters Interceptor, otherwise when the parameters interceptor runs, the model won't be pushed yet, and the setters will be searched on the action, eg. setFname(), instead that on the model (resulting in null properties in the model, and in the warning
Unexpected Exception caught setting 'fname' on 'class RegistrationFormAction: Error setting expression 'fname' with value ['Sumit', ]
because of the missing setters in the action).
Finally, if you are really using the code you posted, then you are NOT using the wrong stack you've created, because 1) The default one is the defaultStack, not the basicStack, so overriding basicStack has no effects, and 2) you've not used <default-interceptor-ref> to change the default stack reference, nor you've used the <interceptor-ref> inside the <action> tag to specify a different interceptor stack for that action only.
You are mixing 1.0.2 and 1.0.3 in DOCTYPE of XML validation files, make everything 1.0.3 (and notice that they migrated from OpenSymphony to Apache); then change:
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
to
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
Ensure that the RegistrationFormAction-validation.xml file is in the action folder, while the RegistrationForm-validation.xml is in the RegistrationForm.java folder.
Consider avoiding ModelDriven, because as Stephen Young says,
You Must Tame Complexity to Become a Better Programmer
As pointed out by AleksandrM's comment, there is also a typo in
<field name="registrationform">
that should be
<field name="registrationForm">
I have a drop down box via the <sj:select> tag that I can't seem to get to populate. I have a getter in the action that it is referencing via the href but it doesn't seem to trigger that action so it isn't seeing the getter. I'm using this method which should work from what I've seen from a few tutorials but I'm apparently missing something somewhere.
In its current state now it's just rendering and empty drop down box.
Quick rundown of what I think should be happening:
page should load via InputAction, which it does and populates the list variable with a list of 20 strings
the <sj:select> should fire off the action referenced in the href
that should trigger the RateClass action which populates my list box
I am going about it this way because based on the input of this box I will be switching in and out lists of strings for future select boxes in this application.
Action Class:
public class RateClass extends InputAction{
/**
*
*/
private static final long serialVersionUID = -836858635953762820L;
private String selectedUtility;
public String execute(){
return SUCCESS;
}
public String getJSON(){
System.out.println("YAY JSON!!!");
return execute();
}
public List<String> getUtilityList() {
return utilityList;
}
public String getSelectedUtility() {
return selectedUtility;
}
public void setSelectedUtility(String selectedUtility) {
this.selectedUtility = selectedUtility;
}
}
Struts.XML json package:
<package name="jsonPackage" extends="json-default" namespace="/">
<action name="rateclass" class="rateclass">
<result name="success" type="json" />
</action>
</package>
Bean Definition:
<bean id="rateclass" class="com.action.input.RateClass" scope="prototype">
</bean>
Relevant .jsp excerpt:
<label for="utility">Utility: </label>
<sj:select style="margin-left:50px;" href="%{remoteurl}" id="utility"
name="selectedUtility" list="utilityList"
headerKey="-1" headerValue="Please Select a Utility"/>
Struts URL definition:
<s:url id="remoteurl" value="rateclass"></s:url>
The issue was in the prepare() function of my InputAction class that was extended off of my JSON class. Inside of that there was a nullpointer being thrown that wasn't handled due to a DAO object I did not define in my RateClass bean.
I have an abstract class that looks like the following with appropriate getters and setters for private properties (left out to keep the post sort):
public abstract class CityDistanceAwareAction extends BaseAction implements Preparable {
private CityDistanceRepository cityDistanceRepository;
private CityRepository cityRepository;
private String cityA;
private String cityB;
private CityDistance cityDistance;
public void prepare() {
if (StringUtils.isNotBlank(cityA) && StringUtils.isNotBlank(cityB)) {
CityPair cityPair = new CityPair(getCityRepository().findByName(cityA), getCityRepository().findByName(cityB));
setCityDistance(getCityDistanceRepository().load(cityPair));
}
}
}
And then I have a very simple Class that looks like the following:
public class SearchCityDistanceAjaxAction extends CityDistanceAwareAction {
#Override
public String perform() {
if (getCityDistance() == null) {
addActionError("No city distance found for that pair");
return ERROR;
}
return SUCCESS;
}
}
The idea is that I can send in a String cityA and String cityB. Do my look-ups and simply return the cityDistance object via AJAX.
When I set my struts.xml action up as follows:
<action name="searchCityDistance" class="searchCityDistanceAjaxAction">
<result type="json">
<param name="includeProperties">
cityDistance.*
</param>
</result>
<result name="error" type="json">
<param name="ignoreHierarchy">false</param>
<param name="includeProperties">
actionErrors.*
</param>
</result>
</action>
I get the following return:
(CommonsLogger.java:68) - Adding include property expression:
cityDistance.* (CommonsLogger.java:68) - [JSON]{}
But I expected to get the cityDistance.* object back provided by the getter in the abstract CityDistanceAwareAction.
Interestingly enough if I add a special getter on the SearchCityDistanceAjaxAction object like the following:
public CityDistance getAjaxCityDistance() {
return getCityDistance();
}
and change the struts file to:
<result type="json">
<param name="includeProperties">
ajaxCityDistance.*
</param>
</result>
It gives me what I expected from my first attempt.
(CommonsLogger.java:68) - Adding include property expression:
ajaxCityDistance.* (CommonsLogger.java:68) -
[JSON]{"ajaxCityDistance":{"cityPair":{"cityA":{"cityName":"American
Falls","id":68},"cityB":{"cityName":"Ririe","id":119}},"distance":85}}
It would be ideal to remove the getter from my SearchCityDistanceAjaxAction as a getter is already provided in the parent. Is there something I am missing here or is this the way it should function?
Thanks in advance.
I was able to change my struts.xml file to the following:
<action name="searchCityDistance" class="searchCityDistanceActionAjaxAction">
<result type="json">
<param name="ignoreHierarchy">false</param>
<param name="excludeProperties">
cityDistanceRepository
</param>
<param name="includeProperties">
cityDistance.*
</param>
</result>
<result name="error" type="json">
<param name="ignoreHierarchy">false</param>
<param name="includeProperties">
actionErrors.*
</param>
</result>
</action>
But it still smells a little fishy to use the excludeProperties to leave out my cityDistanceRepository. If this is how has to be I guess that is what I will do but hopefully there is a better solution.
I have two classes where one inherits the other. I'm trying to map my resultSet to the subclass and Mybatis is ignoring the properties on the superclass (Setters also on the superclass)
Code is as below:
public class CocTreeNode extends CocBean implements TreeNode<CocTreeNode> {
private String level1, level2;
public void setLevel1(String level1){...}
public void setLevel2(String level2){...}
public String getLevel1(){...}
public String getLevel1(){...}
}
public class CocBean {
protected String name;
protected Double volume;
public void setName(String name){...}
public void setVolume(Double volume){...}
public String getName(){...}
public Double getVolume(){...}
}
My resultMap is -
<resultMap id="simpleRow" type="CocTreeNode">
<id property="level1" column="LEVEL1"/>
<id property="level2" column="LEVEL2"/>
<result property="name" column="NAME"/>
<result property="volume" column="VOLUME"/>
</resultMap>
The resulting CocTreeNode objects are populated with 'level1' and 'level2' attributes but not 'name' and 'volume'.
I have tried using extends but that didn't make any difference.
Any ideas will be appreciated.
You have to use extends in your simpleRow resultmap to extend properties from CocBean's resultmap:
<resultMap id="CocBeanResult" type="CocBean">
<result property="name" column="NAME"/>
<result property="volume" column="VOLUME"/>
</resultMap>
<resultMap id="simpleRow" type="CocTreeNode" extends="CocBeanResult">
<result property="level1" column="LEVEL1"/>
<result property="level2" column="LEVEL2"/>
</resultMap>