Spring之手写MVC三大核心组件

前言

本系列终于迎来了第二个核心功能的编写,首先我们Spring里面一共有三个比较重要的核心功能,首先自然是咱们的IOC反转控制DI依赖注入当然还有AOP切面。这一部分的话我们前面看《Spring5核心原理与30个类手写实战 》是已经熟悉,并且照猫画虎实现了一下的,不过我们此时还没有实现AOP部分,而今天的部分呢是MVC部分,实现咱们最核心的功能之一,当然也是最简单的model,后面还有对数据库的支持。那么基本上三个组件就差不多了,那么后面我再根据自己的理解去升级维护(仿造Spring的真实源码)。虽然我们整个系列,包括这本书其实更多地是偏向这个思想,而不是直接看源码,这样首先是我觉得会一头雾水,不知道为啥这样设计,那么自己先看看书,看看大佬的东西,就会对这个总体的思想有一个认识,然后自己去写,然后去想为什么这样写,然后后面结合实际的源码,知道还能怎样优化。

在这里先建议各位小伙伴先前查看前两篇博文。
Spring之手写SpringMVC5个注解

Spring之手写SpringMVC5个注解(之IOC,DI优化)了解三级缓存

坚持到最后文末获取仓库地址。

流程回顾(MVC)

在此之前我们先简单回顾一下最开始的那个版本对于MVC的处理流程,这个非常重要。

首先我们的MVC,其实有两个部分,一个是我们的初始化部分。初始化部分又是分为两个小部分,第一个小部分自然就是我们的IOC部分,第二个部分就是专属于我们MVC的部分。

在这里插入图片描述

之后是我们的分发器,这个是我们MVC的执行组件。
在这里插入图片描述

这个就是我们原来的执行流程,显然我们发现整个步骤还是可以优化的,并且我们还可以添加组件。

MVC 最重要的一点是啥,显然是我们的view和model呀,视图加载和数据渲染呀。

SpringMVC九大组件(了解)

在我们进入我们的内容之前,我们还是需要先简单了解一下我们SpringMVC的九大组件的。

     	initMultipartResolver(context) 多文件上传组件
     	initThemeResolver(context) 初始化模板处理器
        //mvc mapping组件(扫描mvc注解参数)
        initHandlerMappings(context);
        // 参数适配器,匹配参数执行方法
        initHandlerAdapters(context);
        initHandleExceptionResolvers(context) 异常拦截器
        initRequestToViewNameTranslator(context) 初始化视图预处理器
        // 初始化视图转换器
        initViewResolvers(context);
        //FlashMap处理器
        initFlashMapManager(context);

那么今天我们显然想要实现的是

initHandlerMappings(context);
initHandlerAdapters(context);
initViewResolvers(context);

新的流程

ok,回到我们这里,既然我们要说优化,那么显然我们需要实现这三个玩意,那么显然我们需要对现在的流程做一点处理。

初始化流程

这里的话我们主要讨论MVC部分的流程,至于IOC,DI的部分咱们就不关注了这里。对应的代码就是这里
在这里插入图片描述

组件初始化

在这里插入图片描述

初始化干了啥

刚刚看到这个你可能会比较懵逼,那么我门就来说说这三个类到底干了啥。
这里直接看到咱们的流程图
在这里插入图片描述
那么整个过程就是我们的初始化部分。

执行流程

之后就是咱们的执行过程
在这里插入图片描述
首先其前面两个都是老朋友了,主要是后面我们到底干了啥,也就是我们的视图解析部分,到底干了啥。

首先明确一点,我们的通过初始化已经把我们 的html文件和对应的名字都封装起来了,对应的就是我们的ModelandView
在这里插入图片描述
在这里插入图片描述
那么model里面是我们需要渲染的数据,这个部分我们接下来是需要通过我们的模板引擎去做的。

而解析这一切的是我们的入口
在这里插入图片描述
在这里插入图片描述
之后这个view会帮我们做的就是解析模板
在这里插入图片描述
在这里插入图片描述

而之所以会这样,其实重点的诀窍之一还是在我们的adapte里面
在这里插入图片描述
在这里插入图片描述

那么这个就是整个MVC的核心流程。

这里的重点其实就是我们几个被封装的“信息类”,就是那些封装信息的类。

“信息类”

HUHandlerMapping

首先自然就是我们的handlermapping 封装了,我们扫描到的其对应的方法和对应的url(这里是做了正则所以其实是模式)之后是它的controller。

HUModelAndView

这个封装的是视图(你可以理解为html)的名字和我们接下来需要交给解析器渲染的数据。
在这里插入图片描述

当然与之配套的是HUViewResolver

HUViewResolver 与 HUModelAndView 的关系

其实看名字就知道,前者其实是帮助我们加载 后者对应的html 文件和把要解析的数据给模板引擎的。

解析器 HUView

之后的重点是我们的解析器。这里的话是 HUView 这个类。

package com.huterox.spring.framework.webmvc.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HUView {
    
    
    private File viewFile;
    public HUView(File templateFile) {
    
    
        this.viewFile = templateFile;
    }

    public void render(Map<String,?> model, HttpServletRequest req, HttpServletResponse resp) throws IOException {
    
    
        StringBuffer sb = new StringBuffer();//最后输出的内容
        RandomAccessFile ra = new RandomAccessFile(this.viewFile,"r");
        String line = null;
        while (null!=(line=ra.readLine())){
    
    
            line = new String(line.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            Pattern pattern = Pattern.compile("\\$\\{[^\\}]+\\}",Pattern.CASE_INSENSITIVE);
            Matcher matcher = pattern.matcher(line);
            while (matcher.find()){
    
    
                String paramName = matcher.group();
                paramName = paramName.replaceAll("\\$\\{|\\}", "");
                Object paramValue = model.get(paramName);
                line = matcher.replaceFirst(makeStringForRegExp(paramValue.toString()));
                matcher = pattern.matcher(line);
            }
            sb.append(line);
        }
        resp.setCharacterEncoding("UTF-8");
        resp.getWriter().write(sb.toString());
        resp.getWriter().flush();

    }

    public static String makeStringForRegExp(String str){
    
    
        //特殊字符转移
        return str.replace("\\","\\\\").replace("*","\\*")
                .replace("+","\\+").replace("|","\\|")
                .replace("{","\\{").replace("}","\\}")
                .replace("(","\\(").replace(")","\\)")
                .replace("^","\\^").replace("$","\\$")
                .replace("[","\\[").replace("]","\\]")
                .replace("?","\\?").replace(",","\\,")
                .replace(".","\\.").replace("&","\\&");
    }
}

整个核心是我们的正则表达式
用它来渲染数据。在这里插入图片描述

测试

ok 话不多少进入测试环节
在这里插入图片描述

数据渲染ok

项目获取

那么接下来就是获取咱们的项目了。这次的话我是直接上传gitee了,对是直接在gitee

https://gitee.com/Huterox/springcoding

猜你喜欢

转载自blog.csdn.net/FUTEROX/article/details/123502928