Struts2之使用ModelDriven完成的参数自动封装个人理解

前言

struts2提供了通过action实现modeldriven接口而自动封装我们需要的实体对象的功能,这个功能十分实用。因此就在想其实现原理是怎么样的,通过查看源码,得到一些答案,以下是我的理解。

使用ModelDriven的示例

首先需要实体对象

    public class CrmCourseType {

    /**
     * CREATE TABLE `crm_course_type` (
  `courseTypeId` varchar(255) NOT NULL PRIMARY KEY,
  `courseCost` double DEFAULT NULL,
  `total` int(11) DEFAULT NULL,
  `courseName` varchar(500) DEFAULT NULL,
  `remark` varchar(5000) DEFAULT NULL
);
     */
    private String courseTypeId;
    private Double courseCost;
    private Integer total;
    private String courseName;
    private String remark;
    private Set<CrmClass> crmClasses = new HashSet<CrmClass>();


    private String totalStart;
    private String totalEnd;
    private String lessonCostStart;
    private String lessonCostEnd;
    public String getCourseTypeId() {
        return courseTypeId;
    }
    public void setCourseTypeId(String courseTypeId) {
        this.courseTypeId = courseTypeId;
    }
    public Double getCourseCost() {
        return courseCost;
    }
    public void setCourseCost(Double courseCost) {
        this.courseCost = courseCost;
    }
    public Integer getTotal() {
        return total;
    }
    public void setTotal(Integer total) {
        this.total = total;
    }
    public String getCourseName() {
        return courseName;
    }
    public void setCourseName(String courseName) {
        this.courseName = courseName;
    }
    public String getRemark() {
        return remark;
    }
    public void setRemark(String remark) {
        this.remark = remark;
    }
    public Set<CrmClass> getCrmClasses() {
        return crmClasses;
    }
    public void setCrmClasses(Set<CrmClass> crmClasses) {
        this.crmClasses = crmClasses;
    }
    public String getTotalStart() {
        return totalStart;
    }
    public void setTotalStart(String totalStart) {
        this.totalStart = totalStart;
    }
    public String getTotalEnd() {
        return totalEnd;
    }
    public void setTotalEnd(String totalEnd) {
        this.totalEnd = totalEnd;
    }
    public String getLessonCostStart() {
        return lessonCostStart;
    }
    public void setLessonCostStart(String lessonCostStart) {
        this.lessonCostStart = lessonCostStart;
    }
    public String getLessonCostEnd() {
        return lessonCostEnd;
    }
    public void setLessonCostEnd(String lessonCostEnd) {
        this.lessonCostEnd = lessonCostEnd;
    }


}

Aciton类

    public class CourseTypeAction extends ActionSupport implements ModelDriven<CrmCourseType> {

    //
    private CrmCourseType crmCourseType = new CrmCourseType();
    //ervice
    private CourseTypeService courseTypeService;

    public void setCourseTypeService(CourseTypeService courseTypeService) {
        this.courseTypeService = courseTypeService;
    }
    public CrmCourseType getModel() {
        return crmCourseType;
    }


    /**
     * 
     * @return
     */
    public String findAll(){

        List<CrmCourseType> allCourseType = this.courseTypeService.findAll();
        ActionContext.getContext().put("allCourseType", allCourseType);

        return "findAll";
    }
}

另外在JSP表单中的name属性要与实体对象的属性名相同,以上的配置就可以说已经完成了,当访问CourseTypeAction时已经完成了其中的crmCourseType 实例已经封装了参数并且就是当前action中的具体实例,可以拿来直接操作。

实现分析之ModelDriven接口

该接口的作用是返回实例对象,并完成多态,使得在拦截器中可以方便的使用

    public interface ModelDriven<T> {

    /**
     * Gets the model to be pushed onto the ValueStack instead of the Action itself.
     *
     * @return the model
     */
    T getModel();

}

这是该接口中的唯一方法。

实现核心之ModelDrivenInterceptor

其中的参数封装是在ParameterInterceptor拦截器中完成的,暂且不说,返回可以使用的bean对象则是在ModelDrivenInterceptor拦截器中完成的

//核心代码
public String intercept(ActionInvocation invocation) throws Exception {

        //首先获取需要访问的action
        Object action = invocation.getAction();

        //如果action实现了ModelDriven接口
        if (action instanceof ModelDriven) {
            //通过多态将欲访问的action转化成ModelDriven的实现
            ModelDriven modelDriven = (ModelDriven) action;
            //获取ValueStack
            ValueStack stack = invocation.getStack();
            //获取实体对象,这就是必须要在action中new出对象的原因
            Object model = modelDriven.getModel();
            //如果对象存在,则入栈
            if (model !=  null)
                stack.push(model);
            }
            //刷新实例(下面有具体分析)
            if (refreshModelBeforeResult) {
                invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
            }
        }
        return invocation.invoke();
    }

ModelDriven中有一个静态内部类RefreshModelBeforeResult,其作用就是判别在栈中是否有已存在的model实例,如果有就去除并放入当前实例,没有就放入当前的,简而言之就是刷新

 protected static class RefreshModelBeforeResult implements PreResultListener {

        //原始实例
        private Object originalModel = null;
        //实现了ModelDriven 的action对象
        protected ModelDriven action;


        public RefreshModelBeforeResult(ModelDriven action, Object model) {

            this.originalModel = model;
            this.action = action;
        }

        public void beforeResult(ActionInvocation invocation, String resultCode) {
            //获取ValueStack
            ValueStack stack = invocation.getStack();
            //得到ValueStack底层的CompoundRoot实现
            CompoundRoot root = stack.getRoot();

            //一开始设置需要刷新
            boolean needsRefresh = true;
            //得到action中的新实例
            Object newModel = action.getModel();

            // 检查新实例是否已经在栈中
            for (Object item : root) {
                if (item.equals(newModel)) {
                    needsRefresh = false;
                }
            }

            // 将新实例插入栈中
            if (needsRefresh) {

                // 删除原始实例
                if (originalModel != null) {
                    root.remove(originalModel);
                }
                if (newModel != null) {
                    stack.push(newModel);
                }
            }
        }
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Struts2ModelDriven确实只能一次封装成一个实体对象,但是可以通过自定义实现多个实体对象的模型驱动。具体实现方式如下: 1. 定义一个包含多个实体对象的JavaBean,例如: ```java public class MultiModel { private Entity1 entity1; private Entity2 entity2; // 省略getter和setter方法 } ``` 2. 实现ModelDriven接口,重写getModel方法,将多个实体对象封装到MultiModel对象中,并返回MultiModel对象,例如: ```java public class MultiModelDrivenAction implements ModelDriven<MultiModel> { private MultiModel multiModel = new MultiModel(); @Override public MultiModel getModel() { return multiModel; } // 省略其他方法 } ``` 3. 在struts.xml配置文件中将该Action关联到对应的请求,例如: ```xml <action name="multiModelDrivenAction" class="com.example.MultiModelDrivenAction"> <result>/success.jsp</result> </action> ``` 4. 在JSP页面中使用表单提交多个实体对象的数据,并设置对应的name属性,例如: ```html <form action="multiModelDrivenAction" method="post"> <input type="text" name="entity1.field1" /> <input type="text" name="entity1.field2" /> <input type="text" name="entity2.field3" /> <input type="text" name="entity2.field4" /> <input type="submit" value="提交" /> </form> ``` 注意:name属性需要按照MultiModel对象的属性名称进行设置,使用“.”进行分隔。 通过以上步骤,就可以实现一次封装多个实体对象的模型驱动了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值