1.1 新建DispatcherServlet

1.2 在src目录下,新建applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans id="b1">
<bean id="emp" class="xxx.controller.EmpController"/>
<bean id="dept" class="xxx.controller.DeptController"/>
</beans>

1.3 在DispatcherServlet的构造方法中解析applicationContext.xml配置文件

import java.io.IOException;

import java.io.InputStream;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

import org.xml.sax.SAXException;

@WebServlet("*.do")

public class DispatcherServlet extends HttpServlet {

private Map<String, Object> map = new ConcurrentHashMap<>();

public DispatcherServlet() {

try {

InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("applicationContext.xml");

// 1,通过工厂模式,创建documentBuilderFactory工厂对象

DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

// 2,创建DocumentBuilder对象

DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();

// 3,得到Document对象( 注意导入org.w3c.dom包中的)

Document document = documentBuilder.parse(inputStream);

// 4,获得所有的bean标签

NodeList nodeList = document.getElementsByTagName("bean");

for (int i = 0; i < nodeList.getLength(); i++) {

Node node = nodeList.item(i);

if(node.getNodeType() == Node.ELEMENT_NODE) {

//(注意导入org.w3c.dom包中的)

//强转成Element类的对象,里面有比Node类更方便的方法

Element element = (Element)node;

String id = element.getAttribute("id");

String className = element.getAttribute("class");

boolean flag = map.containsKey(id);

if(flag == true)

return;

Object o = Class.forName(className).newInstance();

map.put(id, o);

}

}

} catch (ParserConfigurationException | SAXException | IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {

e.printStackTrace();

}

}

@Override

protected void service(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

// 设置编码

request.setCharacterEncoding("UTF-8");

response.setCharacterEncoding("UTF-8");

response.setContentType("text/html;charset=UTF-8");

// 假设url是: http://localhost:8080/mymvc2/hello.do

// ServletPath是Servlet的访问路径: /hello.do

// 思路是:

// 第1步: /hello.do -> hello 或者 /book.do -> book

// 第2步: hello -> HelloController 或者 book -> BookController

String servletPath = request.getServletPath(); // /hello.do

int lastDotIndex = servletPath.lastIndexOf(".do");

servletPath = servletPath.substring(1, lastDotIndex); // hello

}

}

1.4 在DispatcherServlet的service方法中,通过ServletPath获取对应的Controller对象,优化反射的代码

@Override

protected void service(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

// 设置编码

request.setCharacterEncoding("UTF-8");

response.setCharacterEncoding("UTF-8");

response.setContentType("text/html;charset=UTF-8");

// 假设url是: http://localhost:8080/mymvc2/hello.do

// ServletPath是Servlet的访问路径: /hello.do

// 思路是:

// 第1步: /hello.do -> hello 或者 /book.do -> book

// 第2步: hello -> HelloController 或者 book -> BookController

String servletPath = request.getServletPath(); // /hello.do

int lastDotIndex = servletPath.lastIndexOf(".do");

servletPath = servletPath.substring(1, lastDotIndex); // hello

// 通过ServletPath获取对应的Controller对象

Object xxxController = map.get(servletPath);

String ac = request.getParameter("ac");

System.out.println("=======" + ac + "======");

if (StringUtil.isEmpty(ac))

ac = "index";

try {

// 这里只能try...catch异常,因为在重写的方法里,不能抛出比父类更大的异常

Method method = xxxController.getClass().getDeclaredMethod(ac, HttpServletRequest.class,HttpServletResponse.class);

if (method != null) {

method.invoke(xxxController, request, response);

} else {

throw new RuntimeException("ac值违法");

}

} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException

| InvocationTargetException e) {

e.printStackTrace();

}

}

1.5 写一个简单的EmpController

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

public class EmpController {

public void index(HttpServletRequest request,HttpServletResponse response) {

System.out.println("EmpController...index");

}

}

2. 第二次改进,每一个方法中都有获取参数的代码, 或者都有请求转发或是重定向的代码。解决跳转问题

(代码格式问题各位大佬别吐槽,复制过来的有时间改)

二. 手写SpringMVC框架的更多相关文章

  1. (二)springMvc原理和手写springMvc框架

    我们从两个方面了解springmvc执行原理,首先我们去熟悉springmvc执行的过程,然后知道原理后通过手写springmvc去深入了解代码中执行过程. (一)SpringMVC流程图 (二)Sp ...

  2. 手写SpringMVC框架(二)-------结构开发设计

    续接前文, 手写SpringMVC框架(一)项目搭建 本节我们来开始手写SpringMVC框架的第二阶段:结构开发设计. 新建一个空的springmvc.properties, 里面写我们要扫描的包名 ...

  3. 手写SpringMVC 框架

    手写SpringMVC框架 细嗅蔷薇 心有猛虎 背景:Spring 想必大家都听说过,可能现在更多流行的是Spring Boot 和Spring Cloud 框架:但是SpringMVC 作为一款实现 ...

  4. 手写SpringMVC框架(三)-------具体方法的实现

    续接前文 手写SpringMVC框架(二)结构开发设计 本节我们来开始具体方法的代码实现. doLoadConfig()方法的开发 思路:我们需要将contextConfigLocation路径读取过 ...

  5. 手写SpringMVC框架(一)-------项目搭建

    SpringMVC处理请求的大致流程: 我们来开始着手手写一个SpringMVC框架. 新建一个springMVC项目,流程参见 SpringMVC框架搭建流程 引入servlet相关的jar包: & ...

  6. 纯手写SpringMVC框架,用注解实现springmvc过程

    闲话不多说,直接上代码! 1.第一步,首先搭建如下架构,其中,annotation中放置自己编写的注解,主要包括service controller qualifier RequestMapping ...

  7. 五,手写SpringMVC框架,过滤器的使用

    8. 过滤器 8.1 编写字符过滤器 CharacterEncodingFilter 复制项目mymvc4,新建项目mymvc5 package com.hy.filter; import java. ...

  8. 深度解析SpringMvc实现原理手写SpringMvc框架

    http://www.toutiao.com/a6340568603607171329/?tt_from=mobile_qq&utm_campaign=client_share&app ...

  9. 《四 spring源码》手写springmvc

    手写SpringMVC思路 1.web.xml加载  为了读取web.xml中的配置,我们用到ServletConfig这个类,它代表当前Servlet在web.xml中的配置信息.通过web.xml ...

随机推荐

  1. nginx 配置 https,及加载配置文件夹

    首先需要去申请一个域名签名证书,在腾讯云,阿里云都有免费版,然后下载下来按如下配置,请根据自己路径更改 server { listen 80; server_name xxx.xxx.cn; root ...

  2. 《Shader入门精要》第11章-11.3.1流动的河流中的offset.x的解释

    在我学习入门精要的时候,经常遇到不解释api,甚至是关键代码的实现原理. 11.3.1流动的河流中的offset.x的sin函数查了一下好像大家也都是书上原话直接复制,现在好不容易想明白了希望能帮到和 ...

  3. Github又悄悄升级了,这次的变化是大文件的存储方式

    目录 简介 LFS和它的安装 LFS的使用 从LFS中删除文件 从LFS中拉取代码 转换历史数据到LFS 总结 简介 github是大家常用的代码管理工具,也被戏称为世界上最大的程序员交友网站,它的每 ...

  4. Java GUI 实现发送邮件以及附件

    实现代码: 注意点: 需要的jar包:JavaMail API 和Java Activation Framework (JAF) ,下载可参考菜鸟教程 默认使用QQ邮箱发送,需要设置授权,设置--&g ...

  5. mac电脑sublime text3安装pretty json插件

    因http://packagecontrol.io/地址被墙无法实现自动安装,导致sublime Text3安装插件非常麻烦,总是出现There Are No Packages Available F ...

  6. Python可变参数*args和**kwargs

    本文我们将通过示例了解 Python函数的可变参数*args和 **kwargs的用法. 知识预备:Python 函数和 Python 函数参数 在Python编程中,我们定义一个函数来生成执行类似操 ...

  7. git中的文件操作

    现在我们的机器上有了一个 真实项目 的 Git 仓库,并从这个仓库中检出了所有文件的 工作副本. 通常,你会对这些文件做些修改,每当完成了一个阶段的目标,想要将记录下它时,就将它提交到仓库. git中 ...

  8. “exec: "ssh-keygen": executable file not found in %PATH%” 问题解决

    set PATH=%PATH%;C:\Program Files (x86)\Git\bin bash start.sh 将以上内容保存为start.bat,放在boot2docker根目录下,管理员 ...

  9. crash_for_windows_pkg远程代码执行漏洞

    漏洞详情 crash_for_windows_pkg由 Electron 提供支持.如果 XSS 负载以代理的名义,我们可以远程执行受害者计算机上的任何 JavaScript 代码. 受影响的冲突版本 ...

  10. [AT2306]Rearranging(拓扑序)

    [AT2306]Rearranging(拓扑序) 只有luogu 题面(luogu): 有一个$n$个数组成的序列$a_{i}$. 高桥君会把整个序列任意排列,然后青木君可以选择两个相邻的互质的数交换 ...