栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JAVAWEB实训(1) 编写MVC框架

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JAVAWEB实训(1) 编写MVC框架

目录

1. 什么是MVC框架?

1.1 MVC编程模式

1.2 MVC处理流程 

 2. 编写一个简单的MVC框架

2.1 注解

2.2 处理器映射器HandlerMapping

2.3 中央控制器DispatcherServlet

2.4 梳理MVC流程

 3. 源码


1. 什么是MVC框架?

MVC开始是存在于桌面程序中的,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。

1.1 MVC编程模式

  • V  即View视图,是指用户看到并与之交互的界面。比如由html元素组成的网页界面,或者软件的客户端界面。MVC的好处之一在于它能为应用程序处理很多不同的视图。在视图中其实没有真正的处理发生,它只是作为一种输出数据并允许用户操作的方式。
  • M  即model模型,是指模型表示业务规则。在MVC的三个部件中,模型拥有最多的处理任务。被模型返回的数据是中立的,模型与数据格式无关,这样一个模型能为多个视图提供数据,由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。
  • C  即controller控制器,是指控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。

1.2 MVC处理流程 

【流程图说明】

1.用户发送请求至 前端控制器DispatcherServlet。

2.前端控制器DispatcherServlet收到请求后调用处理器映射器HandlerMapping。

3.处理器映射器HandlerMapping根据请求的Url找到具体的处理器,生成处理器对象Handler及处理器拦截器HandlerIntercepter(如果有则生成)一并返回给前端控制器DispatcherServlet。

4.前端控制器DispatcherServlet通过处理器适配器HandlerAdapter调用处理器Controller。

5.执行处理器(Controller,也叫后端控制器)

6.处理器Controller执行完后返回ModelAnView。

7.处理器映射器HandlerAdapter将处理器Controller执行返回的结果ModelAndView返回给前端控制器DispatcherServlet。

8.前端控制器DispatcherServlet将ModelAnView传给视图解析器ViewResolver。

9.视图解析器ViewResolver解析后返回具体的视图View。

10.前端控制器DispatcherServlet对视图View进行渲染视图(即:将模型数据填充至视图中)

11.前端控制器DispatcherServlet响应用户。

【此处摘自CSDN博主「皓月星辰_w」的原创文章:MVC框架详解(资源整理)_皓月星辰-CSDN博客_mvc框架】

 2. 编写一个简单的MVC框架

观察下面这个类中的方法, 这里指定了url和相应的处理器,那么如何才能让用户在浏览器输入url后,后台正确地调用对应的处理器呢?

2.1 注解

 首先每个方法(处理器)是通过注解与url关联的(value):

  • @Target(ElementType.METHOD)表示是方法注解
  • @Retention(RetentionPolicy.RUNTIME)表示注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解
  • @documented表示这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中,是一个标记注解,没有成员。

ResponseBody:

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@documented

public @interface ResponseBody {
    String value();
}

 ResponseView:

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@documented

public @interface ResponseView {
    String value();
}

 2.2 处理器映射器HandlerMapping

处理器映射器类实际上是一个工具类:建立映射、存储映射、获取处理器

(1) 处理器映射器会在物理上建立url与处理器之间的映射:

private static Map data = new HashMap<>();

 用一个HashMap来保存String类型的url与“处理器对象”之间的映射关系,这个处理器对象我们用一个静态内部类进行封装:

public static class MVCMapping{
    private Object object;
    private Method method;
    private ResponseType type;
}

这是因为我们处理请求的类是通过配置文件进行配置的:application.properties

一个类中间可能包含多个处理请求的方法method,注解的类型表示处理器返回的类型type

(2) 处理器映射器向外提供方法:通过url获取处理器

public static MVCMapping get(String uri)

(3) 处理器能够读取指定流中的处理器类,以方法为单位解析成处理器对象MVCMapping,并生成映射:

public static void load(InputStream is) throws IOException {
        Properties ppt = new Properties();
        ppt.load(is);
        //获取配置文件中描述的一个个类
        Collection values = ppt.values();
        for (Object cla : values) {
            String className = (String) cla;
            try {
                //加载类
                Class c = Class.forName(className);
                //创建对象
                Object object = c.getConstructor().newInstance();
                //获取类的所有方法
                Method[] methods = c.getMethods();
                for (Method m : methods) {
                    Annotation[] annotations = m.getAnnotations();
                    if(annotations!=null) {
                        for (Annotation a : annotations) {
                            if (a instanceof ResponseBody){
                                //说明此方法用于返回字符串给客户端
                                MVCMapping mapping = new MVCMapping(object,m,ResponseType.TEXT);
                                Object o = data.put(((ResponseBody) a).value(),mapping);
                                if(o!=null){//存在的重复的请求地址
                                    throw new RuntimeException("请求地址重复:"+((ResponseBody) a).value());
                                }
                            }else if(a instanceof ResponseView){
                                //说明此方法用于返回界面给客户端
                                MVCMapping mapping = new MVCMapping(object,m,ResponseType.VIEW);
                                Object o = data.put(((ResponseView) a).value(),mapping);
                                if(o!=null){//存在的重复的请求地址
                                    throw new RuntimeException("请求地址重复:"+((ResponseBody) a).value());
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

上面代码中出现的ResponseType是自定义的枚举类型:表示响应的类型

public enum ResponseType {
    TEXT,VIEW;
}

2.3 中央控制器DispatcherServlet

(1)中央处理器继承了HttpServlet,在web.xml中我们对其进行配置:

  • 配置初始化文件
  • 配置处理所有的url请求

    DispatcherServlet
    pers.xls.mvc.DispatcherServlet
    
        contentConfigLocation
        application.properties
    
    0



    DispatcherServlet
    *.do

(2)通过重写Servlet的init方法获取初始化文件:

在这里调用处理器映射类来读取初始化文件建立映射

 @Override
    public void init(ServletConfig config) throws ServletException {
        String path = config.getInitParameter("contentConfigLocation");
        InputStream is = DispatcherServlet.class.getClassLoader().getResourceAsStream(path);
        try {
            HandlerMapping.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

(3)通过重写Service方法,根据接收的请求,获取对应的处理器,进行方法的调用:

 @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取用户请求的uri
        String uri = req.getRequestURI();
        HandlerMapping.MVCMapping mapping = HandlerMapping.get(uri);
        if (mapping==null){
            resp.sendError(404,"自定义MVC:映射地址不存在:"+uri);
            return;
        }
        Object obj = mapping.getObject();
        Method method = mapping.getMethod();
        Object result = null;
        try {
            result = method.invoke(obj,req,resp);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        switch (mapping.getType()){
            case TEXT:
                resp.getWriter().println((String) result);
                break;
            case VIEW:
                resp.sendRedirect((String) result);
                break;
        }
    }

2.4 梳理MVC流程

现在我们来梳理一下这个简单的MVC的处理流程:

  • 通过浏览器我们输入特定的 url 比如:localhost:8080/login.do

  • 中央控制器 DispatcherServlet 处理请求,如果是第一次访问,会调用 init 方法,加载src文件夹下的application.properties配置文件,将文件输入流传递给处理器映射器类 HandlerMapping 进行加载

  • 处理器映射器类 HandlerMapping 加载文件输入流,读取配置文件中的处理器类,分析出类中的含有特定注解的方法,建立url到“处理器对象MVCMapping”的映射,存储在哈希表中

  • 中央控制器 DispatcherServlet 继续调用service方法,调用处理器映射器类 HandlerMapping 的 get 方法获取请求uri对应的“处理器对象”。如果获取不到,说明不存在该访问地址到处理器的映射,访问的内容不存在。从获取到的“处理器对象”中提取出相关的处理类对象、方法、响应类型,利用Java的反射机制,调用该方法:

         获取响应值,最后根据响应类型的不同对前台进行响应:

 3. 源码

链接:https://pan.baidu.com/s/1kfZAc-Z6DmK0cp1pcEfX7Q 
提取码:g8zx

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/298129.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号