ModelDriven的简单使用

ModelDriven需要在action中实现ModelDriven接口,然后重写getModel()方法,在执行action的时候会先执行getModel方法,获取封装的对象。

有如下实体类:

public class Offer {

    private Integer offerId;    //提供者Id
    private String offerName;   //提供者名称
    private String offerMail;   //提供者邮箱
    private String offerMobile; //提供者手机号

    public Integer getOfferId() {
        return offerId;
    }

    public void setOfferId(Integer offerId) {
        this.offerId = offerId;
    }

    public String getOfferName() {
        return offerName;
    }

    public void setOfferName(String offerName) {
        this.offerName = offerName == null ? null : offerName.trim();
    }

    public String getOfferMail() {
        return offerMail;
    }

    public void setOfferMail(String offerMail) {
        this.offerMail = offerMail == null ? null : offerMail.trim();
    }

    public String getOfferMobile() {
        return offerMobile;
    }

    public void setOfferMobile(String offerMobile) {
        this.offerMobile = offerMobile == null ? null : offerMobile.trim();
    }
}

与Offer相对应的action,OfferAction:

public class OfferAction extends WebActionSupport implements ModelDriven<Offer> {

    @Autowired
    private OfferManager offerManager;

    private Offer Offer;

    private Integer pageSize = 15;

    /**
     * 修改或新增
     * 
     * @return
     * @throws Exception
     */
    public String save() throws Exception {
        String errorMessage = validateForm();
        if(StringUtils.isBlank(errorMessage)){
            if (rmOffer.getOfferId() != null) {
                Offer dataOffer = offerManager.selectByPrimaryKey(offer.getOfferId());
                dataOffer = offer;
                offerManager.update(dataOffer);
                WebUtil.returnJSON(response, "{\"successSign\" : true}", "json");
            } else {
                offerManager.add(offer);
                WebUtil.returnJSON(response, "{\"successSign\" : true}", "json");
            }
        }else{
            String jsonData = "{\"successSign\":false,\"errorMessage\":" + "\"" +errorMessage + "\""+ "}";
            WebUtil.returnJSON(response, jsonData, "json");
        }
        return null;
    }

    /**
     * 修改页面赋值
     * 
     * @return
     * @throws Exception
     */
    public String input() throws Exception {
        if (offer.getOfferId() != null) {
            Offer dataOffer = offerManager.selectByPrimaryKey(offer.getOfferId());
            request.setAttribute("dataOffer", dataOffer);
        }
        return "input";
    }



    private String validateForm() {
        if (StringUtils.isBlank(offer.getOfferName())) {
            return "提供者名称不能为空";
        } else if (offer.getOfferName().length() < 2 || offer.getOfferName().length() > 20) {
            return "提供者名称长度为2~20个字符";
        }

        if (StringUtils.isBlank(offer.getOfferMail())) {
            return "提供者邮箱不能为空";
        } else if (!offer.getOfferMail().matches("^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$")) {
            return "提供者邮箱格式不正确";
        }

        if (StringUtils.isBlank(offer.getOfferMobile())) {
            return "提供者电话不能为空";
        } else if (!offer.getOfferMobile().matches("((\\d{11})|^((\\d{7,8})|(\\d{4}|\\d{3})-(\\d{7,8})|(\\d{4}|\\d{3})-(\\d{7,8})-(\\d{4}|\\d{3}|\\d{2}|\\d{1})|(\\d{7,8})-(\\d{4}|\\d{3}|\\d{2}|\\d{1}))$)")) {//支持手机号码,3-4位区号,7-8位直播号码,1-4位分机号
            return "提供者电话格式不对";
        }

        return null;
    }

    @Override
    public Offer getModel() {
        if (offer == null) {
            offer = new Offer();
        }
        return offer;
    }

    public Offer getOffer() {
        return offer;
    }

    public void setOffer(Offer offer) {
        this.offer = offer;
    }

}

对应的添加或修改的jsp:

<form id="sendForm" name="sendForm" class="search-form"  action="">
        <input type="hidden" name="offerId" value="${dataRmOffer.offerId}">
        <div class="search-box" style="clear: both;margin:20px 0;">
            <label for="offerId">提供者名称:</label>
            <input type="text" name="offerName" value="${dataOffer.offerName}">
        </div>
        <div class="search-box" style="clear: both;margin:20px 0;">
            <label for="offerMail">提供者邮箱:</label>
            <input type="text" name="offerMail" value="${dataOffer.offerMail}">
        </div>
        <div class="search-box" style="clear: both;margin:20px 0;">
            <label for="offerMobile">提供者手机号:</label>
            <input type="text" name="offerMobile" value="${dataOffer.offerMobile}">
        </div>
        <div style="clear: both;padding-top:20px;" >
            <a href="javascript:void(0)" id="submit-btn" class="button button-blue button-m">确定</a>
            <a href="#content/rm-offer.action" id="cancel-btn" class="button button-blue button-m">取消</a>
        </div>
    </form>

在执行execute方法前(虽然例子里面没有execute方法),会先执行getModel()方法,其实在执行action中相关方法前都会先执行getModel()方法获取相关对象。这种方式就省去了从前台一个个拿表单数据的麻烦,不用再自己new 对象一个个赋值,使得代码更简洁一点,出符合面向对象的思想。

其中有一个隐含的bug就是在执行更新方法的时候,也就是例中save()方法带offerId的情况,input()方法要从数据库中取值赋值到input页面,要先自己从数据库中查到这个Offer,而不能直接引用getModel方法获得的对象,因为getModel中总是一个新的从前台封装好过来的对象(当然不是前台来封装,应该说struts来封装),直接引用会使得input页面的text框中无数据(但id是有的),原因就是前台使用了input页面封装的Offer,只而跳转到input页面只包含了id属性。解决办法就是如上所说,自己查到offer对象,返回查到的对象。当然,ModelDrivenInterceptor提供了一个配置参数:refreshModelBeforeResult,只要把它定义为true,上术问题也能解决,意思就是把旧的model对象从ValueStack中移除,然后再把新的model对象压入ValueStack。

ModelDriven的机制:
先看看ModelDriven的原码~

public class ModelDrivenInterceptor extends AbstractInterceptor {

    protected boolean refreshModelBeforeResult = false;

    public void setRefreshModelBeforeResult(boolean val) {
        this.refreshModelBeforeResult = val;
    }

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        Object action = invocation.getAction();

        if (action instanceof ModelDriven) {
            ModelDriven modelDriven = (ModelDriven) action;
            ValueStack stack = invocation.getStack();
            Object model = modelDriven.getModel();
            if (model !=  null) {
                stack.push(model);
            }
            if (refreshModelBeforeResult) {
                invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
            }
        }
        return invocation.invoke();
    }

这段代码是ModelDrivenInterceptor中的,他是缺省拦截器链的一部分,执行action的时候会先判断该action是否实现了modelDriven接口,如果是,执行getModel()方法,并把值压入值栈。下面这个方法就是刚才说的refreshModelBeforeResult属性。

protected static class RefreshModelBeforeResult implements PreResultListener {
        private Object originalModel = null;
        protected ModelDriven action;


        public RefreshModelBeforeResult(ModelDriven action, Object model) {
            this.originalModel = model;
            this.action = action;
        }

        public void beforeResult(ActionInvocation invocation, String resultCode) {
            ValueStack stack = invocation.getStack();
            CompoundRoot root = stack.getRoot();

            boolean needsRefresh = true;
            Object newModel = action.getModel();

            // Check to see if the new model instance is already on the stack
            for (Object item : root) {
                if (item.equals(newModel)) {
                    needsRefresh = false;
                    break;
                }
            }

            // Add the new model on the stack
            if (needsRefresh) {

                // Clear off the old model instance
                if (originalModel != null) {
                    root.remove(originalModel);
                }
                if (newModel != null) {
                    stack.push(newModel);
                }
            }
        }
    }

By the way:那个invoke()方法, 就是通知struts2接着干下面的事情比如调用下一个拦截器或执行下一个Action。

学习的时候如下博客给了很大帮助:http://blog.csdn.net/li_tengfei/article/details/6098145

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值