zoukankan      html  css  js  c++  java
  • JavaWeb之搭建自己的MVC框架(一)

    1. 介绍

            MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。

            我们今天就来搭建一个自己的从URL访问到JAVA控制器的简单框架。

    2. 准备

            首先,我们应该对JAVA的反射机制、Servlet最基本原理、以及JAVA注解有所了解。不了解的读着可先学习:

    3. 实现思路

    • 首先,我们要将URL访问请求和我们的后台JAVA方法形成一一对应关系。
    • 然后,我们需要在tomcat容器启动网站加载的时候获取上一步骤中记录的一一对应关系,并记录下来。
    • 最后,完成URL访问到后台JAVA方法的跳转。

    4. 实现方式:

            (1)通过注解来标记出URL到后台JAVA方法的映射关系。

            A.    定义注解:这个注解可以标注在类和方法上。

    package com.mvc.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface URLMapping {    
        public String url() default "";
    }

            B.    JAVA后台中针对URI的相应方法:

    package com.mvc.controller;
    
    import com.mvc.annotation.URLMapping;
    
    @URLMapping(url="/Say")
    public class SayController{
        
        @URLMapping(url="/Hello")
        public String SayHello(){
            System.out.println("Hello");
            return "Hello";
        }
        
        @URLMapping(url="/Hi")
        public String SayHi(){
            System.out.println("Hi");
            return "Hi";
        }
        
    }

            通过注解,我们可以看出我们拟定将来用SayController这个类来相应/Say/***的URL。其中SayHello方法相应的URL是/Say/Hello,SayHi方法相应的URL是/Say/Hi。

            这样,我们就定义好了URL和JAVA后台方法的对应关系。接下来我们要实现如果完成这种对应关系的跳转

            (2)实现URL到JAVA后台方法的跳转

            A.    定义我们用来存储URL到JAVA后台方法对应关系的基础数据类型:

    package com.mvc.base;
    
    public class MVCBase {
        private String url; //我们将来要访问的URL
        private String controller; //这个URL对应的后台JAVA类
        private String method; //这个URL对应的后台方法名称
            
        public String getUrl() {
            return url;
        }
        public void setUrl(String url) {
            this.url = url;
        }
        public String getController() {
            return controller;
        }
        public void setController(String controller) {
            this.controller = controller;
        }
        public String getMethod() {
            return method;
        }
        public void setMethod(String method) {
            this.method = method;
        }    
    }

            B.    通过监听器在tomcat启动的时候收集URL到JAVA后台方法的对应关系并存储起来:

    package com.mvc.listener;
    
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import com.mvc.annotation.URLMapping;
    import com.mvc.base.MVCBase;
    
    public class UrlMappingCollection implements ServletContextListener {
        //被注解了URLMapper的类方法列表
        private static List<MVCBase> mvcBases;
    
        //我们要扫描的Controller列表
        private final String[] controllerList = {"com.mvc.controller.SayController"}; 
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            // TODO Auto-generated method stub
        }
    
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            mvcBases = new ArrayList<MVCBase>();
            
            try {
                //循环所有需要扫描的Controller
                for (int i = 0; i < controllerList.length; i++) {
                    String controllerName = controllerList[i]; 
                    
                    String classURL = "";
                    String methodURL = "";
                    
                    Class<?> clazz = Class.forName(controllerName); //获取Controller类
                    if (clazz.isAnnotationPresent(URLMapping.class)) { //class被标记了URLMapping注解
                        classURL = ((URLMapping) clazz.getAnnotation(URLMapping.class)).url();             
                    }
                    //获取method列表
                    Method[] methods = clazz.getMethods();
                    for (Method method : methods) {
                        if (method.isAnnotationPresent(URLMapping.class)) { 
                        //method被标记了URLMapping注解
                            methodURL = ((URLMapping) method.getAnnotation(URLMapping.class)).url(); 
                            
                            MVCBase mvcBase = new MVCBase();
                            mvcBase.setUrl(classURL+methodURL);
                            mvcBase.setController(controllerName);
                            mvcBase.setMethod(method.getName());
                            
                            mvcBases.add(mvcBase);
                        }
                    }
                }
            }
            catch (Exception e) {
                
            }
        }
        
        public static List<MVCBase> getMvcBases() {
            return mvcBases;
        }
    
    }
      • mvcBases就是将来我们要将URL到JAVA后台方法对应关系存储到的地方。我们将他定义为静态方法,以便后续我们直接访问获取。
      • controllerList是用来告诉监听器,我们要从哪些类中获取URL到JAVA后台方法的对应关系。因为在程序设计期我们就已经知道了,所以定义为final属性。
      • 然后在监听器初始化的时候,循环controllerList中的class,根据注解的信息来收集URL到JAVA后台方法的对应关系并存储到mvcBases中。

            C.    配置Servlet访问:

                首先我们要准备我们的Servlet类,将来所有的URL请求都要跳转到这个Servlet中。

    package com.mvc.servlet;
    
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import com.mvc.base.MVCBase;
    import com.mvc.listener.UrlMappingCollection;
    
    public class ServletCenter extends HttpServlet {
        private static final long serialVersionUID = -1163369749078348562L;
    
        private void doTransfer(HttpServletRequest req, HttpServletResponse resp) 
                throws ServletException, IOException, ClassNotFoundException, 
                       SecurityException, NoSuchMethodException, IllegalArgumentException, 
                       IllegalAccessException, InvocationTargetException, 
                       InstantiationException    {        
            for (MVCBase mvcBase : UrlMappingCollection.getMvcBases()) {
                if (req.getRequestURI().equals(
                                   req.getServletContext().getContextPath()+mvcBase.getUrl())) {
                    Class<?> clazz = Class.forName(mvcBase.getController());
                    Method method = clazz.getMethod(mvcBase.getMethod());
                    method.invoke(clazz.newInstance());
                }
            }
        }
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
                  throws ServletException, IOException {
            try {
                doTransfer(req, resp);
            } catch (Exception e) {
                
            }
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
                  throws ServletException, IOException {
            try {
                doTransfer(req, resp);
            } catch (Exception e) {
                
            }
        }
    }

            可以看到,doGet和doPost里面都执行的是doTransfer方法。相应的web.xml配置为:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="3.0" 
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
                            http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">    
        <listener>
            <listener-class>com.mvc.listener.UrlMappingCollection</listener-class>
        </listener>                        
                            
        <servlet>
            <servlet-name>main</servlet-name>
            <servlet-class>com.mvc.servlet.ServletCenter</servlet-class>        
        </servlet>
        <servlet-mapping>
            <servlet-name>main</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>

              在web.xml中,我们将所有的请求都跳转到com.mvc.servlet.ServletCenter中。

    5. 测试

            将MyMVC部署到tomcat容器中,启动tomcat,输入http://127.0.0.1:8080/MyMVC/Say/Hello 以及http://127.0.0.1:8080/MyMVC/Say/Hi 就可以看到后台输出的Hello和Hi了。

    6. 目录结构

    QQ截图20160323214532

    笔者只是初学者,开此博客的初衷是为了给自己的学习过程留一个痕迹。所以您可能发现笔者措辞不严谨、逻辑不合理,甚至代码有错误、结论很偏颇等等。笔者感激各位的讨论和指正,并在此不胜感激!拜谢!欢迎加QQ群讨论:852410026
  • 相关阅读:
    canvas
    canvas基础
    canvas基础
    面向对象
    函数的原型链
    原型链&Object的一些方法
    普通函数和构造函数
    下载RDO OpenStack RPM
    RHEL7修改swappiness
    2016年新年愿望
  • 原文地址:https://www.cnblogs.com/LOVE0612/p/5313266.html
Copyright © 2011-2022 走看看