2013-03-29 33 views
1

我想要一个表单来创建类型层次结构中的几个子类之一。说它是AbstractPerson的子类Employee和Visitor。struts2形式的抽象类

我可以使用单一的Action/REST-Controller Bean吗?

通常我使用form-ids smart,所以它直接给我的Action的setters赋值。 所以,如果我有一个像

AbstractPerson member; 

成员,我会尝试使用形式称为“member.name”的输入字段。

但是,struts必须首先创建一个AbstractPerson的实例 - 并且它不能因为它是抽象的!如果我能给struts2一个暗示它应该实际创建一个Empolyee或Visitor对象(取决于表单内容),这将是非常酷的。这是可能吗?

干杯!

+0

看看[类型转换](http://struts.apache.org/release/2.0.x/docs/type-conversion.html)文档。 –

回答

3

这类似于我最近通过一小组crud操作访问实体类的方法。这是少数的粗暴行为,允许您在特定包中的所有实体类上进行操作。您应该能够将此策略应用于您的员工和访问者类。

它是如何工作简而言之:

1)你必须在任何命名空间或动作的名称应创建类的名称来指定。

2)您使用struts2s prepareable接口来创建模型。 (反射创建从步骤1确定的类。

3)使用模型驱动的接口,它返回在步骤2中定义的对象。这样,该对象位于堆栈的顶部,您可以简单地说“name”并且知道它是在步骤1中确定的类的名称属性。您可以避免这一步,但它不是很漂亮。

现在出现这样一个小问题,你会发现要执行上述三个步骤,你需要一个定制的堆栈,一个“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的结果类型。

+0

+1延迟加载可以通过'excludeProperties'来避免。 –

+0

定制堆栈的好主意! – clemens

+0

@RomanC但是当通过名称空间参数在运行时确定实体类时,我排除了哪些属性? – Quaternion