zoukankan      html  css  js  c++  java
  • java写个自己的mvc框架学习笔记

    1. 介绍

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

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

    附加:在我的 github上有一个初版的 swift-framework 框架(与本节内容无关)

    swift是一个轻量级的web框架,实现了 IOC、MVC、ORM 功能,并且已经可以使用,满足基本的开发需要和学习使用,适合了解spring的基本原理。
    未来将会逐步实现 aop、安全管理等功能。

    2. 实现思路

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

    3. 具体实现:

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

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

    /**
     * @author 旺旺
     */
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface UrlMapping {
        public String url() default "";
    }

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

    package mvc;
    
    /**
     * @author 旺旺
     */
    @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 mvc;
    
    /**
     * @author 旺旺
     */
    public class MVCBase {
        private String url;//访问路径
        private String controller;//类名
        private String method;//方法名
        
        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 mvc;
    
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    
    /**
     * @author 旺旺
     */
    public class UrlMappingCollection implements ServletContextListener {
    
        //被注解了URLMapper的类方法列表
        private static List<MVCBase> mvcBases;
        
        //我们要扫描的Controller列表
        private final String[] controllerList = {"mvc.SayController"};
        
        public void contextDestroyed(ServletContextEvent arg0) {
            
        }
    
        public void contextInitialized(ServletContextEvent arg0) {
            mvcBases = new ArrayList<MVCBase>();
            try {
                //循环所有需要扫描的Controller
                for(String controllerName : controllerList) {
                    String classUrl = "";
                    String methodUrl = "";
                    
                    //获取Controller类
                    Class<?> clas = Class.forName(controllerName);
                    //class被标记了URLMapping注解
                    if(clas.isAnnotationPresent(UrlMapping.class)) {
                        classUrl = clas.getAnnotation(UrlMapping.class).url();
                        
                        //获取method列表
                        Method[] methods = clas.getMethods();
                        for(Method method : methods) {
                            if(method.isAnnotationPresent(UrlMapping.class)) {
                                methodUrl = method.getAnnotation(UrlMapping.class).url();
                                
                                MVCBase mvc = new MVCBase();
                                mvc.setUrl(classUrl + methodUrl);
                                mvc.setController(controllerName);
                                mvc.setMethod(method.getName());
                                
                                mvcBases.add(mvc);
                            }
                        }
                        
                    }
                    
                    
                }
            } 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 mvc;
    import
    java.io.IOException; import java.lang.reflect.Method; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author 旺旺 */ public class ServletCenter extends HttpServlet { /** * */ private static final long serialVersionUID = 1L;
      private static boolean lock = true;
    
    

        //实例容器,注册表
        private static HashMap registry = new HashMap();

        
        @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) {
                
            }
        }
        
        //通过url执行对应的方法
        private void doTransfer(HttpServletRequest req, HttpServletResponse resp) 
                throws Exception{ 
        
    //遍历url容器 for(MVCBase mvcBase : UrlMappingCollection.getMvcBases()) { //判断注解路径 if(req.getRequestURI().equals(req.getContextPath() + mvcBase.getUrl())) { //反射获取class Class<?> clas = Class.forName(mvcBase.getController()); //获取方法 Method method = clas.getMethod(mvcBase.getMethod()); //执行方法

              if(mvcBase.getController() != null) {
                //捕获异常,特殊处理。。。。
                //设置单例
                if(registry.get(mvcBase.getController()) == null) {
                  try {

                    synchronized(lock) { //防止多线程造成冲突

                      //添加单例放入注册表
                      registry.put(mvcBase.getController(), Class.forName(mvcBase.getController()).newInstance());

                    }
                  } catch(Exception ex) {
                    ex.printStackTrace();
                  }
                }
                //获取单例,执行方法
                method.invoke(registry.get(mvcBase.getController()));
              } else {
                //特殊处理。。。
              }

    
                }
            }
            
        }
    
    }

    可以看到,doGet和doPost里面都执行的是doTransfer方法。

    相应的web.xml配置为:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.5" 
        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_2_5.xsd">
      <display-name></display-name>    
      <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
      
      <!-- 配置监听器 -->
      <listener>
              <listener-class>mvc.UrlMappingCollection</listener-class>
      </listener>
      
      <servlet>
              <servlet-name>hello</servlet-name>
              <servlet-class>mvc.ServletCenter</servlet-class>
      </servlet>
      <servlet-mapping>
              <servlet-name>hello</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了

    如果还对 Spring 的AOP、IOC、ORM感兴趣的,可以看看我写的轻量级框架 swift-framework 框架,简单易懂,而且可用。包含了Spring 中的基本核心功能。

    Git 地址 :https://github.com/zwwjava/swift-framework

     
  • 相关阅读:
    day13 python学习 迭代器,生成器
    day12 python学习 装饰器
    day10 python学习 函数的嵌套命名空间作用域 三元运算 位置参数 默认参数 动态参数
    day11 python学习 函数的建立,返回值,参数
    day7 python学习
    2易错概念和点
    day8 python学习 集合 深浅拷贝
    1.易错概念和点
    python_基础算法
    css基础示例代码
  • 原文地址:https://www.cnblogs.com/zhaww/p/8467574.html
Copyright © 2011-2022 走看看