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

 

java写个自己的mvc框架学习笔记的更多相关文章

  1. Java基础及JavaWEB以及SSM框架学习笔记Xmind版

    Java基础及JavaWEB以及SSM框架学习笔记Xmind版 转行做程序员也1年多了,最近开始整理以前学习过程中记录的笔记,以及一些容易犯错的内容.现在分享给网友们.笔记共三部分. JavaSE 目 ...

  2. Spring框架学习笔记(5)——Spring Boot创建与使用

    Spring Boot可以更为方便地搭建一个Web系统,之后服务器上部署也较为方便 创建Spring boot项目 1. 使用IDEA创建项目 2. 修改groupid和artifact 3. 一路n ...

  3. Spring框架学习笔记(8)——spring boot+mybatis plus+mysql项目环境搭建

    之前写的那篇Spring框架学习笔记(5)--Spring Boot创建与使用,发现有多小细节没有提及,,正好现在又学习了mybatis plus这款框架,打算重新整理一遍,并将细节说清楚 1.通过I ...

  4. spring mvc 及NUI前端框架学习笔记

    spring mvc 及NUI前端框架学习笔记 页面传值 一.同一页面 直接通过$J.getbyName("id").setValue(id); Set值即可 二.跳转页面(bus ...

  5. phalcon(费尔康)框架学习笔记

    phalcon(费尔康)框架学习笔记 http://www.qixing318.com/article/phalcon-framework-to-study-notes.html 目录结构   pha ...

  6. JavaSE中Collection集合框架学习笔记(2)——拒绝重复内容的Set和支持队列操作的Queue

    前言:俗话说“金三银四铜五”,不知道我要在这段时间找工作会不会很艰难.不管了,工作三年之后就当给自己放个暑假. 面试当中Collection(集合)是基础重点.我在网上看了几篇讲Collection的 ...

  7. JavaSE中Collection集合框架学习笔记(3)——遍历对象的Iterator和收集对象后的排序

    前言:暑期应该开始了,因为小区对面的小学这两天早上都没有像以往那样一到七八点钟就人声喧闹.车水马龙. 前两篇文章介绍了Collection框架的主要接口和常用类,例如List.Set.Queue,和A ...

  8. JavaSE中Map框架学习笔记

    前言:最近几天都在生病,退烧之后身体虚弱.头疼.在床上躺了几天,什么事情都干不了.接下来这段时间,要好好加快进度才好. 前面用了三篇文章的篇幅学习了Collection框架的相关内容,而Map框架相对 ...

  9. JavaSE中线程与并行API框架学习笔记1——线程是什么?

    前言:虽然工作了三年,但是几乎没有使用到多线程之类的内容.这其实是工作与学习的矛盾.我们在公司上班,很多时候都只是在处理业务代码,很少接触底层技术. 可是你不可能一辈子都写业务代码,而且跳槽之后新单位 ...

随机推荐

  1. LeeTCode题解之Remove Duplicates from Sorted List

    1.题目描述 2.问题分析 对于链表中的每一个元素,找到其后面和它不相等的第一个元素,然后指向该元素. 3.代码 ListNode* deleteDuplicates(ListNode* head) ...

  2. android编写测试类

    由于网上很多教程,我就不多说.在这里我就说说我遇到的问题. 在android studio编写单元测试类中,在androidTest包下编写了两个类,分别如下 import junit.framewo ...

  3. linux date 简单介绍

    用法:date [选项]... [+格式] 或:date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]] 以给定的格式显示当前时间,或是设置系统日期. - ...

  4. excel如何冻结首行或首列及首行首列同时冻结

    冻结首行方法: 首先选择首行,在菜单栏选择视图菜单,再选择冻结窗格下拉三角里的冻结首行即可. 效果如下:拖动垂直滚动条 冻结首列方法: 首先选择首列,在菜单栏选择视图菜单,再选择冻结窗格下拉三角里的冻 ...

  5. 【转】Nginx学习---Nginx&&Redis&&hcache三层缓存架构总结

    [原文]https://www.toutiao.com/i6594307974817120782/ 摘要: 对于高并发架构,毫无疑问缓存是最重要的一环,对于大量的高并发,可以采用三层缓存架构来实现,n ...

  6. pig:group by之后的其它统计方法一

    --测试Top N后的其它统计 A = LOAD '/TraceParser/blackcore/' USING PigStorage() as (lk_id:chararray,host:chara ...

  7. 如何删除sharepoint列表List中的全部数据。

    可以使用excel,但是powershell会比较方便 (admin mode - Sharepoint powershell) [System.reflection.Assembly]::LoadW ...

  8. 【Python】【unittest】unittest测试框架中setup,teardown与setupclass,teardownclass的区别

    # -*- coding:utf-8 -*- import unittest def runTest(testcaseclass,testcase=[]): suite = unittest.Test ...

  9. Mac上编译OpenJDK过程记录

    编译OpenJDK主要为了学习HotSpot,编译过程在很多相关书籍中都有所涉及,但由于机型.机子具体环境的不同,很难有资料能够一步到位.还是得碰到具体问题通过上网查来一个个解决. 下载OpenJDK ...

  10. svn: 无法连接主机“127.0.0.1”: 拒绝连接

    尝试搭建SVN服务器,前面的步骤都OK,服务已经启动, svnserve -d --listen-port 80 --listen-host 0.0.0.0 -r /data/nerrissa/svn ...