Using struts2 json plugin - java

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.

Related

How to solve the MyBatis Pagination PageHelper query return data has duplicates?

When I use MyBatis Pagination PageHelper, the query returns are duplicates. I think should not be!, because will affect the duplicate problem when I query two tables. For example what I wrote the sql mapping file,the following code:
SELECT
o.id,
o.uid,
u.nickname,
o.order_num,
o.order_type,
o.order_price,
o.pay_type,
o.order_status,
o.name,
o.phone,
o.delivery_time,
o.createtime
FROM
orders AS o,
water_member AS u
WHERE
o.order_status = 1
ORDER BY
o.id
DESC
But is has repetitions:
UnpaidOrderController.java
#RestController
public class UnpaidOrderController {
#Autowired
private UnpaidOrderService unpaidOrderService;
#RequestMapping(value = "unpaidorder",method = RequestMethod.GET)
public Object getByPage(#RequestParam(value = "pageNo", defaultValue = "1") int pageNo,
#RequestParam(value = "pageSize", defaultValue = "3") int pageSize) {
Page<UnpaidOrder> list = unpaidOrderService.findByPage(pageNo, pageSize);
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg","查询成功");
jsonObject.put("data",list);
return jsonObject;
}}
UnpaidOrderMapper.java
#Mapper
public interface UnpaidOrderMapper {
Page<UnpaidOrder> findByPage();
}
UnpaidOrderService.java
public interface UnpaidOrderService {
Page<UnpaidOrder> findByPage(int pageNo, int pageSize);}
UnpaidOrderServiceImpl.java
#Service
public class UnpaidOrderServiceImpl implements UnpaidOrderService {
#Autowired
private UnpaidOrderMapper unpaidOrderMapper;
public Page<UnpaidOrder> findByPage(int pageNo, int pageSize) {
PageHelper.startPage(pageNo,pageSize);
return unpaidOrderMapper.findByPage();
}
}
UnpaidOrderMapper.xml
<mapper namespace="com.zyl.water.mapper.UnpaidOrderMapper">
<!-- 映射订单对象的resultMap -->
<resultMap id="BaseResultMap" type="UnpaidOrder">
<result column="id" property="id" />
<result column="uid" property="uid" />
<result column="nickname" property="nickname" />
<result column="order_num" property="order_num" />
<result column="order_type" property="order_type" />
<result column="pay_type" property="pay_type" />
<result column="order_status" property="order_status" />
<result column="name" property="name" />
<result column="phone" property="phone" />
<result column="delivery_time" property="delivery_time" />
<result column="createtime" property="createtime" />
</resultMap>
<!-- 查询未支付订单 -->
<select id="findByPage" resultMap="BaseResultMap">
SELECT
o.id,
o.uid,
u.nickname,
o.order_num,
o.order_type,
o.order_price,
o.pay_type,
o.order_status,
o.name,
o.phone,
o.delivery_time,
o.createtime
FROM
orders AS o,
water_member AS u
WHERE
o.order_status = 1
ORDER BY
o.id
DESC
</select>
I wanted to comment on your strategy to paginate.
This is not an issue of MyBatis, but of your query. When paginating you need to specify a UNIQUE ordering set of columns.
The reason of this is that in SQL, rows do NOT have a specific ordering by default. Therefore, the database will return them in any order when the ORDER BY clause is not specific enough. This way "Page 1" and "Page 2" may end up showing a few/lot identical rows.
Every time the query is executed (every time you click "Next Page") the row order must be clearly specified, but it's not in your case.

Struts action class properties are getting null after using myinterceptors

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>

How to perform XML Validation when using ModelDriven?

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">

Struts2 not showing String Attribute

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.

Mybatis - Inherited properties not being mapped

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>

Categories

Resources