zoukankan      html  css  js  c++  java
  • Struts2 自定义MVC框架

    一、Model1与Model2:

    Model1:就是一种纯jsp开发技术,将业务逻辑代码和视图渲染代码杂糅在一起。

    Model2:Model2是在Model1的基础上,将业务逻辑的代码分离开来,单独形成一个Servlet,Model2也是基于MVC开发

    二、MVC设计模式:

    由3个部分组成,各部分作用如下:

    Model:模型,主要用于数据和业务的处理

    View:视图,用于数据的显示

    Controller:控制器,用于进行流程控制

    MVC设计模式的特点:

    ①一个模型可以对应多个视图

    ②显示与逻辑控制的分离

    ③分层控制,减轻了代码间的耦合


    自定义MVC框架只需dom4j.jar包即可!

     三、准备XML文档Framework.xml

    注意点:

    <!-- ELEMENT 表示元素 -->
    <!-- ATTLIST 表示属性 -->
    <!-- CDATA 表示字符串类型 -->
    <!-- REQUIRED 表示此属性必须的写 -->
    <!-- *代表多个 -->
    <!-- IMPLIED 表示此属性可写 -->

    复制代码
    <!DOCTYPE Framework[
    <!ELEMENT Framework (actions)>
    <!ELEMENT actions (action*)>
    <!ELEMENT action (result*)>
    
    <!ATTLIST action name CDATA #REQUIRED
                     class CDATA #REQUIRED
    >
    
    
    <!ATTLIST RESULT name CDATA #IMPLIED
                     redirect (true|false) "false"
    >
    
    ]>
    
    <Framework>
    <actions>
    <action name="loginAction" class="cn.happy.action.LoginAction">
    <result name="success">success.jsp</result>
    <result name="login">index.jsp</result>
    </action>
    </actions>
    </Framework>
    复制代码


    四、定义自己的Action接口,用于存放结果集和要执行的方法

    复制代码
    public interface Action {
        //定义两个静态字符串常量(逻辑视图名)
        public static final String SUCCESS="success";
        public static final String LOGIN="login";
        //定义一个抽象方法execute
        public String execute(HttpServletRequest request,HttpServletResponse response)throws Exception;
    
    }
    复制代码

    五、定义ActionMapping类用于存放Action节点,即一个ActionMapping类可以视为配置文件中的一个action节点

    复制代码
    public class ActionMapping {
        //根据action节点中的属性 以及action节点中的<result></result>节点定义三个私有属性
        
        private String name;//action的名称
        private String classname;//action对应程序中的类
        private Map<String,String> results=new HashMap<String,String>();
        
        //向results集合中添加数据的方法
        public void addResult(String name,String value){
            results.put(name, value);
        }
    
        //根据名称获取的方法
        public String getResults(String name){
            return results.get(name);
        }
        
        public Map<String, String> getResults() {
            return results;
        }
        public void setResults(Map<String, String> results) {
            this.results = results;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getClassname() {
            return classname;
        }
        public void setClassname(String classname) {
            this.classname = classname;
        }
        
    复制代码

    六、定义ActionMappingManager类用于管理ActionMapping,并通过dom4j解析Framework.xml配置文件。从而获取根节点,以及actions节点,并通过for循环遍历actions节点下的action节点拿到name和class的属性值,由于一个action节点下有多个result节点 及遍历action下所有的result节点,分别存入到actionMapping中的双列集合中,最后得到所有action节点的集合

    复制代码
    public class ActionMappingManager {
        //actionMapping类的集合
        private Map<String,ActionMapping> maps=new HashMap<String,ActionMapping>();
    
        public ActionMapping getActionMapping(String name){
            return maps.get(name);
        }
        
        //解析src下所有配置文件
        public ActionMappingManager(String[]files){
            for (String filename : files) {
                init(filename);
            }
        }
        
        //创建初始化方法,使用dom4j解析配置文件
        public void init(String path){
            try {
                 //getResourceAsStream取得该资源输入流的引用保证程序可以从正确的位置抽取数据
                InputStream is=this.getClass().getResourceAsStream("/"+path);
                //解析XML
                Document doc=new SAXReader().read(is);
                //获取根节点
                Element root = doc.getRootElement();
                //获取actions节点
                 Element actions =(Element)root.elementIterator("actions").next();
                 //使用for循环来
                 //遍历actions节点下的所有action节点
                 for (Iterator<Element> action=actions.elementIterator("action");action.hasNext();) {
                    //获取到action节点
                     Element actionnext = action.next();
                    //分别获取到action节点中的name属性和class属性
                     String name=actionnext.attributeValue("name");
                     String classname=actionnext.attributeValue("class");
                     //将以上两个属性保存到ActionMapping类中
                     ActionMapping mapp=new ActionMapping();
                     mapp.setClassname(classname);
                     mapp.setName(name);
                     //由于一个action节点下有多个result节点 遍历action下所有的result节点
                     for (Iterator<Element> result=actionnext.elementIterator("result");result.hasNext();){
                         //获取到result节点
                         Element resultnext = result.next();
                         //提取result节点的name属性值和result节点中的值
                         String resultname= resultnext.attributeValue("name");
                        String resultvalue= resultnext.getText();
                         //将其分别存入到actionMapping中的双列集合中去,方便调用actionMapping类(actionMapping类中就有数据了!)
                        mapp.addResult(resultname, resultvalue);
                     }
                    //得到所有action节点的集合
                     maps.put(mapp.getName(), mapp);
                 }
            
            } catch (Exception e) {
                
            }
        }
    复制代码

    七、使用反射机制根据字符串类型的类名获取到具体的类--ActionManager

    复制代码
    public class ActionManager {
    
        public static Action getActionClass(String classname){
            Class clazz=null;
            Action action=null;
            //获取当前线程的加载类
            try {
                clazz=Thread.currentThread().getContextClassLoader().loadClass(classname);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            
            if(clazz==null){
                try {
                    //如果该线程中没有,那么使用class.forname方法获取
                    clazz=Class.forName(classname);
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
            
            if(action==null){
                //将获取到的类型转换为action,调用无参构造函数,某种程度上相当于new,不过new需要指定类型
                try {
                    action =(Action)clazz.newInstance();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            return action;
        }
    复制代码

    八、定义Servlet类,详情见注释!注意点在web.xml中添加 <load-on-startup>节点,让程序一开始就初始化servlet

    复制代码
    public class MyServlet extends HttpServlet {
    
        
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
               doPost(request,response);
            
        }
    
        ActionMappingManager man=null;
        public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
              //获取到ActionMapping对象
            ActionMapping actionMapping=man.getActionMapping(getname(request));
            //获取action接口利用反射机制
            Action action = ActionManager.getActionClass(actionMapping.getClassname());
            try {
                String message=action.execute(request, response);
                String results=actionMapping.getResults(message);
                response.sendRedirect(results);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
            //获取请求路径名
            public String getname(HttpServletRequest request)
            {
                //项目+请求地址
                String requestURI =request.getRequestURI();
                //项目名称
                String contextPath=request.getContextPath();
                //具体的请求
                String path=requestURI.substring(contextPath.length());
                String filename=path.substring(1,path.lastIndexOf(".")).trim();
                return filename;
            
            }
        
        //重写servlet的init方法,让程序一开始就初始化servlet
        //由于一个项目src根目录下有可能有多个配置文件,不止一个,所以逐个解析
            
        @Override
        public void init(ServletConfig config) throws ServletException {
            
            //初始化参数信息
            String filename = config.getInitParameter("config");
            String [] filenames=null;
            
            if(filename==null){
                //如果没有别的参数信息,就将已经配好的放入数组中
                filenames=new String[]{"Framework.xml"};
            }
            else{
                //拆分配置文件名称字符串
                filenames=filename.split(",");
            }
            //使用init方法初始化
            man=new ActionMappingManager(filenames);
        }
    复制代码

    九、业务逻辑Action并实现Action接口,并重写自定义的execute方法

    复制代码
    public class LoginAction implements Action{
    
        public String execute(HttpServletRequest request,
                HttpServletResponse response) throws Exception {
            String name=request.getParameter("name");
            String pwd=request.getParameter("pwd");
            if(name.equals("1")&&pwd.equals("1")){
                return SUCCESS;
            }
            else{
                return LOGIN;
            }
        }
    复制代码

    十、编写登录界面

    复制代码
      <body>
         <form action="loginAction.action" method="post">
        姓名:<input type="text" name="name"/><br/>
        密码:<input type="text" name="pwd"/><br/>
        <input type="submit" value="登录">
        </form>
      </body>
    复制代码

     实现效果:

  • 相关阅读:
    使用 Dockerfile 定制镜像
    UVA 10298 Power Strings 字符串的幂(KMP,最小循环节)
    UVA 11090 Going in Cycle!! 环平均权值(bellman-ford,spfa,二分)
    LeetCode Best Time to Buy and Sell Stock 买卖股票的最佳时机 (DP)
    LeetCode Number of Islands 岛的数量(DFS,BFS)
    LeetCode Triangle 三角形(最短路)
    LeetCode Swap Nodes in Pairs 交换结点对(单链表)
    LeetCode Find Minimum in Rotated Sorted Array 旋转序列找最小值(二分查找)
    HDU 5312 Sequence (规律题)
    LeetCode Letter Combinations of a Phone Number 电话号码组合
  • 原文地址:https://www.cnblogs.com/jingpeipei/p/5989259.html
Copyright © 2011-2022 走看看