天天看点

二. 手写SpringMVC框架

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. 第二次改进明天再写,每一个方法中都有获取参数的代码, 或者都有请求转发或是重定向的代码。解决跳转问题

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