• Struts(十七):通过CURD来学习paramsPrepareParams拦截器栈


    • 背景:

    通过上一章节《Struts(十六):通过CURD来学习Struts流程及ModelDriven的用法》学习了ModelDriven拦截器的用法,上章节中讲到了edit功能。

    要修改一个member信息时:

    1、首先通过url传入一个id参数:member-list.jsp中

                <td><s:a href="member-view.action?id=%{id}" >view</s:a></td>
                <td><s:a href="member-edit.action?id=%{id}" >edit</s:a></td>            
                <td><s:a href="member-delete.action?id=%{id}" >delete</s:a></td>

    2、MemberAction.java的edit函数:

        public String edit() {
            // 1、根据id从数据库中,获取id对应的member对象
            Member member_ = memberDao.get(this.member.getId());
            
            // 2、把从数据库中获取的属性放入值栈的属性中
            this.member.setAge(member_.getAge());
            this.member.setName(member_.getName());
            this.member.setGender(member_.getGender());
            
            return "edit";
        }

    3、表单form-edit.jsp:

        <s:debug></s:debug>
        <s:form action="member-save.action">
            <s:textfield name="id" label="ID"></s:textfield>
            <s:textfield name="name" label="Name"></s:textfield>
            <s:textfield name="age" label="Age"></s:textfield>
            <s:radio list="#{'male':'male','female':'female' }" name="gender" label="Gender"></s:radio>
            <s:submit name="submit" label="提交"></s:submit>
        </s:form>

    流程分析图:

    根据上边的代码,调试form-edit.jsp页面当打开s:debug我们确实看到了栈顶对象被填充值了:

    4、修改MemberAction.java的edit方法,并调试产看member-edit.jsp debug内容:

        public String edit() {
    //        // 1、根据id从数据库中,获取id对应的member对象
    //        Member member_ = memberDao.get(this.member.getId());
    //        
    //        // 2、把从数据库中获取的属性放入值栈的属性中
    //        this.member.setAge(member_.getAge());
    //        this.member.setName(member_.getName());
    //        this.member.setGender(member_.getGender());
    //        
            this.member= memberDao.get(this.member.getId());
    
            return "edit";
        }

    这是为什么呢?

    ---getModel()返回的对象是存放在栈顶的对象,而修改后的对象是Dao中返回的对象,这两个对象不是同一个对象的原因。

    我们是否能通过其他方式来实现这个功能呢?

    • 自动填写了memeber-edit.jsp表单页面改写方案(paramsPrepareParamsStack方案)

    方案一:把重新赋值后的this.member对象压入栈顶

        public String edit() {
            // // 1、根据id从数据库中,获取id对应的member对象
            // Member member_ = memberDao.get(this.member.getId());
            //
            // // 2、把从数据库中获取的属性放入值栈的属性中
            // this.member.setAge(member_.getAge());
            // this.member.setName(member_.getName());
            // this.member.setGender(member_.getGender());
    
            this.member = memberDao.get(this.member.getId());
            ActionContext.getContext().getValueStack().push(this.member);
    
            return "edit";
        }

    不错这样是可以自动填写了memeber-edit.jsp表单页面,但是我们查看s:debug下发现值栈中有两个member对象:

    方案二:使用paramsPrepareParams拦截器栈

    1、修改struts.xml来实现修改当前项目struts2的拦截器栈

    在package标签下添加配置:<default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref>

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
    
    <struts>
        <constant name="struts.ognl.allowStaticMethodAccess" value="true" />
        <constant name="struts.devMode" value="false" />
    
        <package name="default" namespace="/" extends="struts-default">
            <default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref>
            <action name="member-*" class="com.dx.struts.actions.MemberAction"
                method="{1}">
                <result name="{1}">/member-{1}.jsp</result>
                <result name="delete" type="redirectAction">member-list</result>
                <result name="modify" type="redirectAction">member-list</result>
                <result name="create" type="redirectAction">member-list</result>
            </action>
        </package>
        <!-- Add packages here -->
    </struts>

    2、对MemberAction.java进行修改:

    1)添加id属性,并实现其set方法,目的是:实现在调用ModelDriven的getModel函数前,通过Params调用该set方法实现对id属性赋值,因此可以在getModel内部使用该属性判定是否页面传递了该参数。

    2)修改MemberAction.java自身方法。

    修改后代码如下:

    /**
     * @author Administrator
     *
     */
    package com.dx.struts.actions;
    
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.struts2.interceptor.RequestAware;
    
    import com.opensymphony.xwork2.ActionContext;
    import com.opensymphony.xwork2.ModelDriven;
    
    import com.dx.struts.dao.MemberDao;
    import com.dx.struts.entity.Member;
    
    /**
     * ModelDriven 和Preparable拦截器
     */
    public class MemberAction implements RequestAware, ModelDriven<Member> {
        private MemberDao memberDao = new MemberDao();
        private Member member;
        private Long id;
    
        // Params拦截器 负责赋值id时,调用了该函数。
        public void setId(Long id) {
            this.id = id;
        }
    
        public String list() {
            List<Member> members = memberDao.getMembers();
            request.put("members", members);
            return "list";
        }
    
        public String view() {
            // // 1、获取传入的id:member.getId();
            // // 2、根据id获取member对象;
            // Member member_ = memberDao.get(this.member.getId());
            //
            // // 3、赋值栈顶对象的属性:此时栈顶对象为member对象。
            // member_.setAge(this.member.getAge());
            // member_.setName(this.member.getName());
            // member_.setGender(this.member.getGender());
            //
            return "view";
        }
    
        public String delete() {
            // memberDao.remove(this.member.getId());
            memberDao.remove(this.id);
            // 返回结果的类型应该为:redirectAction
            // 也可以是chain:实际上chain是没有必要的,因为不需要在下一个action中保留啊当前action的状态
            // 若使用chain,则到达目标页面后,地址栏显示的依然是删除的那个链接,则刷新时会重复提交。
            return "delete";
        }
    
        public String edit() {
            // // 1、根据id从数据库中,获取id对应的member对象
            // Member member_ = memberDao.get(this.member.getId());
            //
            // // 2、把从数据库中获取的属性放入值栈的属性中
            // this.member.setAge(member_.getAge());
            // this.member.setName(member_.getName());
            // this.member.setGender(member_.getGender());
    
            // this.member = memberDao.get(this.member.getId());
            // ActionContext.getContext().getValueStack().push(this.member);
    
            return "edit";
        }
    
        public String save() {
            //....
    
            return "modify";
        }
    
        public String create() {
            member.setId(new Date().getTime());
            memberDao.add(member);
    
            return "create";
        }
    
        private Map<String, Object> request;
    
        @Override
        public void setRequest(Map<String, Object> request) {
            this.request = request;
        }
    
        @Override
        public Member getModel() {
            // 如果需要在这个函数调用调用了ModelDriven拦截器栈之前就初始化参数id的拦截器栈的Params拦截器。
            // 经过查看DefaultStack拦截器栈中ModelDriven拦截器之前并没有Params拦截器,说明该默认拦截器已经不够用了,
            // 但是我们发现在struts2-core.jar下struts-default.xml下除了DefaultStack拦截器栈外还有paramsPrepareParamsStack拦截器栈,
            // 而该拦截器栈中恰好在ModelDriven拦截器栈之前和之后都调用了一次Params拦截器。
            // 修改struts.xml package标签下添加配置:<default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref>
    
            // 如果没有id请求参数,说明为create
            if (this.id == null) {
                this.member = new Member();
            }
            // 如果有id请求参数,说明为edit
            else {
                this.member = memberDao.get(this.id);
            }
            return this.member;
        }
    }
    • 值栈paramsPrepareParamsStack方案总结

     不足之处(资源浪费):

    1、在执行删除的时候,id不为null,但是getModel方法执行了一次从数据库中空加载;

    2、当执行查询信息时,也空执行了一次new Member()对象。

  • 相关阅读:
    CodeForces
    hdu4003 树形dp
    hdu2196
    poj2486
    hdu1502 树形dp入门题
    cf 686D
    bzoj2763 分层图
    hdu4424 并查集+贪心+思维
    poj1734 最小环+输出路径
    集训题解1
  • 原文地址:https://www.cnblogs.com/yy3b2007com/p/6635515.html
Copyright © 2020-2023  润新知