通过阅读springMVC的源码之后,我们已经对SpringMVC 的核心功能有了一个大概的思路,SpringMVC如何让一个用户在浏览器输入一个URL就能得到它想要的视图或数据集,这个流程中他做了一些什么处理,下面我们总结下一个请求到获得结果过程中主要的几个节点:
1、配置一个web容器来接收客户端请求。
2、当客户端输入一个URL请求发送到服务器首先进入我们的DispatchServlet。
3、然后我们拿到用户输入的ULR后根据URL识别出用户想要调用的controller 和controller里面的method。
4、找到对应的method 后我们还需要把用户传递过来的参数传递给method。
5、知道了方法和参数之后就可以执行method了,执行完方法后拿到method的返回值。
6、拿到方法的返回值之后,我们再根据用户的返回值来区分用什么样的视图解析技术进行视图解析(比如说,Json,jsp,html,freemarker等等)。
7、最后根据对应的视图解析把用户返回的参数解析成html页面或者Json数据响应给客户端。
![0708b21b6baef74e17c4831b9575777b.png](https://i-blog.csdnimg.cn/blog_migrate/147929f1b4f1402c4dbba4d5250f90a3.jpeg)
当然springmvc还有很多的细节需要处理,编码设置、语言设置、统一异常处理、文件上传处理等等,我们这里就只来模仿核心的几个流程实现SpringMVC功能,下面我们就根据几个核心节点来仿造一个springMVC。
1、配置一个web容器来接收客户端请求
这里我们使用tomcat 作为一个web容器,springmvc还需要IOC容器的支撑,这里我们会引用之前的IOC容器代码。
1-1、定义一个DispatchServlet作为http请求的统一入口,在初始化方法里对IOC容器进行初始化,IOC容器实现过程和代码见上一篇文章 勤劳的小手:仿造一个spring IOC。
package com.dp;
import com.dp.anotation.MyRequestMapping;
import com.dp.core.HandleAdapter;
import com.dp.core.HandleMapping;
import com.dp.core.ModelAndView;
import com.dp.core.View;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by Administrator on 2019/8/27.
*/
public class MyDispatcherServlet extends HttpServlet {
private MyApplicationContext applicationContext=null;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
/**
* 容器初始化
* @throws ServletException
*/
@Override
public void init() throws ServletException {
// 初始化IOC容器
applicationContext=new MyApplicationContext("application.properties");
}
@Override
public void destroy() {
System.out.println("容器销毁=============");
super.destroy();
}
}
配置web.xml 指定程序入口和需要加载的配置文件
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>MyDispatcherServlet</servlet-name>
<servlet-class>com.dp.MyDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocationg</param-name>
<param-value>classpath:application.properties</param-value> <!--初始化加载文件-->
</init-param>
</servlet>
<!--拦截所有请求-->
<servlet-mapping>
<servlet-name>MyDispatcherServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
2、当客户端输入一个URL请求发送到服务器首先进入我们的MyDispatcherServlet。
在web.xml里面我们已经配置了MyDispatcherServlet会处理所有的请求,所以我们这里只需要增加一个doDispatcher方法对GET,POST等所有的请求进行统一的处理。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doDispatcher(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doDispatcher(req, resp);
}
/**
* 统一请求处理
* @param req
* @param resp
*/
private void doDispatcher(HttpServletRequest req, HttpServletResponse resp) {
}
3、然后我们拿到用户输入的ULR后根据URL识别出用户想要调用的controller 和controller里面的method。
3-1、定义
首先我们要定义一个对象(HandleMapping)专门保存url、controller、method对应的关系。
package com.dp.core;
import lombok.Data;
import java.lang.reflect.Method;
@Data
public class HandleMapping {
//请求URL
private String url;
//URL对应的contrller
private Object controller;
//URL对应的方法
private Method method;
public HandleMapping(String url, Object controller, Method method) {
this.url = url;
this.controller = controller;
this.method = method;
}
}
3-2、初始化
然后在容器初始化扫描IOC容器中所有带有MyRequestMapping 注解的的方法,然后把MyRequestMapping 注解的URL和controller、method关系保存起来。
定义注解: