我想有一个表单,创建一个类型层次结构中的几个子类之一。假设它是AbstractPerson,具有子类Employee和Visitor。
我可以用单个动作/rest -控制器Bean做到这一点吗?
通常我使用form-ids智能,所以它直接将值分配给我的Action的setter。如果我有一个成员,比如
AbstractPerson member;
我将尝试使用一个带有名为"member.name"的输入字段的表单。
然而,struts必须首先创建一个AbstractPerson的实例——这是不可能的,因为它是抽象的!如果我能给struts2一个提示,它实际上应该创建一个employee或Visitor对象(取决于表单内容),那将是非常酷的。那样或类似的事情可能吗?
干杯!
这类似于我最近通过一组crud操作访问Entity类。也就是说,一些粗糙的操作允许您操作特定包中的所有实体类。您应该能够将此策略应用于Employee和Visitor类。
简而言之:
1)您需要在名称空间或操作名称中指定应该创建的类的名称。
2)使用struts2的可准备接口来创建模型。(反射地创建从步骤1确定的类。
3)使用模型驱动的接口,它返回步骤2中定义的对象。这样,该对象位于堆栈的顶部,您可以简单地说"name",并知道它是在步骤1中确定的类的name属性。你可以避免这一步,但它不是那么漂亮。
现在这样做有一个小故障,您会发现要执行上面的三个步骤,您需要一个自定义堆栈,一个"staticParams-prepare-params"堆栈。
首先是一个例子,然后是堆栈的定义,让它工作,请告诉我,如果你有任何问题:
package com.quaternion.demo.action.crud;
import com.quaternion.demo.orm.ActionValidateable;
import com.quaternion.demo.service.CrudService;
import com.quaternion.demo.util.ActionUtils;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.springframework.beans.factory.annotation.Autowired;
// Adds a new record to the database
@ParentPackage("staticParams-prepare-parms")
@Namespace("/crud/{entityName}")
@Result(type = "kjson") //TODO: could rid of this line by setting the result as the default for the package
public class AddAction extends ActionSupport implements Preparable, ModelDriven {
private static final Logger log = Logger.getLogger(AddAction.class.getName());
@Autowired
private CrudService crudService;
private String entityName;
private Object entityModel;
private Map jsonModel = new HashMap(); //for output, return the newly created object
private Class clazz;
@Override
public String execute() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
log.log(Level.INFO, "In execute entityName is set with {0}", entityName);
//If an id is passed in it will merge the object with that id, null will be used for unset attributes
String status = SUCCESS;
boolean error = false;
Object entity = null;
try {
entity = crudService.create(clazz, entityModel);
} catch (Exception e) {
error = true;
status = ERROR;
jsonModel.put("message", e.getMessage());
}
if (error == false) {
jsonModel.put("entity", entity);
}
jsonModel.put("status", status);
return SUCCESS;
}
public Object getEntityModel() {
return entityModel;
}
public void setEntityModel(Object entityModel) {
this.entityModel = entityModel;
}
public Object getJsonModel() {
return jsonModel;
}
@Override
public Object getModel() {
return this.entityModel;
}
@Override
public void prepare() throws Exception {
log.log(Level.INFO, "In prepare entityName is set with {0}", entityName);
clazz = ActionUtils.initClazz(entityName);
entityModel = clazz.newInstance();
}
public String getEntityName() {
return entityName;
}
public void setEntityName(String entityName) {
this.entityName = entityName;
}
//TODO: validation would be a good idea can't implement in this class need to delegate
//if entity implements a validate method, this validate should
//call that validate
@Override
public void validate(){
if (entityModel instanceof ActionValidateable){
((ActionValidateable)entityModel).validate(this);
}
}
}
下面是堆栈的定义:
<package name="staticParams-prepare-parms" extends="struts-default">
<result-types>
<result-type name="kjson" default="true" class="com.quaternion.demo.result.Kjson"/>
</result-types>
<interceptors>
<interceptor-stack name="staticParamsPrepareParamsStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo..*,^struts..*,^session..*,^request..*,^application..*,^servlet(Request|Response)..*,parameters...*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="staticParamsPrepareParamsStack"/>
</package>
您可能想知道kjson结果类型是什么。我觉得struts2-json插件在其他几个动作上的挑战。我创建了一个通用的分页和读取操作,"flexjson"默认情况下不序列化集合,这可以防止延迟加载问题(在没有加载集合的情况下,这些简单的服务总是会出现这种情况),所以kjson只是一个使用flexjson返回json的结果类型。