在前面Web工程的web.xml中有个servlet-class标签,配置值为org.springframework.web.servlet.DispatcherServlet,这个类是springMVC的入口。
DispatcherServlet继承了FrameworkServlet,打开spring-webmvc-4.3.9.RELEASE-sources.jar,在这个类的源代码里可以看出public class DispatcherServlet extends FrameworkServlet。
FrameworkServlet又继承了HttpServlet类,并重写了两个重要的方法doGet(HttpServletRequest request, HttpServletResponse response)和doPost(HttpServletRequest request, HttpServletResponse response)。其实Servlet主要作用就是把这两个方法实现了。
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Delegate POST requests to {@link #processRequest}.
* @see #doService
*/
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
下面我们来自定义一个Servlet类,名为PersonServlet,分别实现doGet和doPost方法。
package com.helloworld.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class PersonServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("servlet get method"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }在doGet方法里,使用resp.getWriter()获得一个Writer对象,再调用.write("servlet get method")输出一个字符串。在doPost()方法里,直接再调doGet方法,也就是post请求会使用doGet的逻辑。get和post在基础教程里也提到过,两者都是http协议的请求方法,用来处理用户的请求操作。
在web.xml中加入这个新的servlet配置,在servlet标签中,servlet-name为personservlet,servlet-class为com.helloworld.servlet.PersonServlet。在servlet-mapping标签中,对应同样的servlet-name为personservlet,url-pattern为/getPerson。这里的url-pattern和Controller中的@RequestMapping都是配置要访问的url地址的。
重新部署这个Web工程,访问地址http://localhost/calculateWeb/getPerson,浏览器就会输出servlet中的信息“servlet get method”。
下面再改一下PersonServlet,把doGet中的resp.getWriter().write("servlet get method");这句去掉,换成
req.setAttribute("message", "servlet doGet");
req.getRequestDispatcher("/index.jsp").forward(req, resp);
重新部署后再访问,显示也改为了<span font-size:medium;white-space:normal;"="" style="word-wrap: break-word; margin: 0px; padding: 0px;">servlet doGet。这种req.getRequestDispatcher("/index.jsp").forward(req, resp)跳转到jsp显示的方式与前面resp.getWriter()的方式有所不同,但都做到了显示数据,只是这种方式把显示界面用jsp来实现了。
到这里可以看出,Servlet能够做到和Controller实现类似的功能。通过比较也可以看出,Spring的Controller可以更简化配置和代码编写。在没有springMVC之前,早期的Web工程很多都是用原生Servlet实现的,而springMVC框架使用一个DispatcherServlet就可以把请求分发给各个Controller对象,大大简化了Web工程的开发。
用户访问Web工程的某个url,是由DispatcherServlet调用其内部的doDispatch方法来分发请求的。在DispatcherServlet的源码中,doDispatch(HttpServletRequest request, HttpServletResponse response)这个方法会调用mv = ha.handle(processedRequest, response, mappedHandler.getHandler());这个语句,跟着进入AbstractHandlerMethodAdapter的handler()方法,执行mv = ha.handle(processedRequest, response, mappedHandler.getHandler());这句,再跟着会进入RequestMappingHandlerAdapter的handleInternal()方法,执行ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod)语句。在这个handleInternal()方法里,有一句mav = invokeHandlerMethod(request, response, handlerMethod);就是把request和response对象传给Controller并调用相应的方法handlerMethod,比如这里handlerMethod就是public java.lang.String com.helloworld.controller.PersonController.helpToDo(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse),这样Java的反射机制就可以把这个PersonController的helpToDo发起执行。这个过程就是springMVC的Controller内部工作原理。
Java视频教程