当用户向服务器发送请求时。
在servlet阶段,用户发送请求后,servlet端会接收用户端传来的数据,并通过service层进行业务的处理,再将处理后的结果,通过请求转发或者重定向的方式,反馈给用户。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); System.out.println(username); req.setAttribute("username", username); req.getRequestDispatcher("/test/a.jsp").forward(req,resp); }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
|
在整个过程中,我们需要再web.xml文件中配置相应的Servlet。当用户发送不同的请求,我们就需要创建不同的Servlet程序,并且在xml文件中进行配置。
1 2 3 4 5 6 7 8
| <servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class>servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/helloServlet</url-pattern> </servlet-mapping>
|
但是,在实际的开发过程中,一个web工程有很多不同的功能,如果这样,用户发送不一样的请求,就要新建一个servlet,就要配置一个servlet,这样会让代码冗余,而且工作量也十分大。那么怎么解决这个问题呢? SpringMVC很好的解决了这个问题。
在SpringMVC中,你不需要编写servlet程序,因此也不需要在 web.xml中对其进行配置。springMVC对其进行了分离,当用户发送请求时,SpringMVC会通过前端控制器(DispatcherServlet)对用户的请求进行拦截和过滤,分别通过处理器映射、处理器适配、视图解析器处理之后,将结果渲染到视图上。而在此过程中,在处理器适配完成之后,会找到相应的控制器(Controller),进行业务的执行。整个springMVC的执行看下图:
根据上图可以得出具体的执行原理:
1.用户发送请求之后,请求由前端控制器(DispatcherServlet)接收,前端控制器是整个SpringMVC框架的核心。
2.HandlerMapping,即处理器映射,会根据用户的请求来映射对应的Handler,即处理器。
3.HandlerExecution,即处理器执行,通过处理器的执行来找到相应的控制器。
4.将得到的控制器返回
5.HandlerAdapter,处理器适配,根据特定的规则去查找适配的处理器。
6.Controller,控制器,执行适配的处理器,并处理具体的业务,再将ModelAndView返回给前端控制器
7.ViewResolver,视图解析器,将ModelAndView进行解析,并渲染到视图上
其实,在使用springMVC进行web开发的过程中,我们不需要关心前端控制器是如何来进行过滤拦截等操作的,我们只需要关注业务层的相关代码以及Controller,其他SpringMVC已经帮我们在底层实现了,我们直接用就可以了。但是为了搞清楚整个执行过程是很有必要的,可以帮助我们更好的去理解SpringMVC的优点。
编写一个实例如下:
前面说到,一切的工作都是由前端控制器来执行的,因此需要再web.xml配置DispatcherServlet的参数信息,设置参数,绑定到相对应的spring配置文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
|
配置好前端控制器,那么当用户发送请求的时候,就会被它所过滤和拦截。
接下来,按照图中的信息,我们需要三个部分的处理,分别是:处理器映射、处理器适配、视图解析。这些事情全部都在spring的配置文件中去配置,先上代码:
1 2 3 4 5 6 7 8 9 10 11
|
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean>
|
先不管上述代码,前面说到,我们只需要编写Controller以及业务层的相关代码就可以了,那Controller程序怎么编写呢?其实spring为我们提供了一个Controller接口,我们只需要去实现这个接口就可以了。
1 2 3 4 5 6 7 8 9 10
| import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.lang.Nullable; import org.springframework.web.servlet.ModelAndView;
@FunctionalInterface public interface Controller { @Nullable ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception; }
|
可以看出,Controller是一个函数型接口, 里面只有一个方法,而该方法刚好返回的就是一个ModelAndView对象,正是我们所需要的.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class HelloController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { ModelAndView modelAndView = new ModelAndView();
String result = "HelloSpringMVC"; modelAndView.addObject("msg", result); modelAndView.setViewName("test");
return modelAndView; } }
|
我们需要先new一个ModelAndView对象,然后调用业务方法完成业务操作,紧接着设置要跳转的页面,最后将视图返回。假设我们的业务是在对应的页面上打印“HelloSpringMVC”,addObject方法类似于req.serAttribute()方法, 参数是K-V的形式。最后,在spring配置文件中,初始化bean对象
1 2
| <bean id="/hello" class="com.springmvc.controller.HelloController" />
|
想必你还是不是很理解springMVC到底是怎么执行的,那么就对应着具体代码来分析。
首先,我们需要一个前端控制器,而这个前端控制器需要与网页进行交互,因此需要再web.xml文件中配置,而这个类springMVC已经为我们提供好了。并且,有上面的大致分析可以看出,前端控制器需要通过处理器映射、处理器适配对用户的请求进行相关的业务操作,最后再由视图解析对结果进行渲染。那么,通过一个spring的配置文件来实现一系列的操作。
处理器的映射与执行:*假定用户现在访问的是这个url: http://localhost:8080/hello, 那么通过处理器的映射后拿到url,在通过处理器的执行器来查找对应的控制器,即“/hello”*
1 2 3
|
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
|
处理器适配; *前端控制器会将处理器进行适配,找到符合要求的控制器,即Controller,再由它进行业务操作*
1 2
| <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
|
通过上面两个步骤,*就可以准确的找到对应的控制器,而这个控制器就是spring中配置的这个bean对象*
1 2
| <bean id="/hello" class="com.springmvc.controller.HelloController" />
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class HelloController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { ModelAndView modelAndView = new ModelAndView();
String result = "HelloSpringMVC"; modelAndView.addObject("msg", result); modelAndView.setViewName("test");
return modelAndView; } }
|
HelloController经过操作以后返回了一个ModelAndView实例,上面的代码可以看出当完成业务之后,视图会跳转到指定的页面,而其中只设置了一个”test” , 很显然,这不是一个完整的页面url,因此,视图解析器需要出场了:
1 2 3 4 5 6
| <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean>
|
*** 视图解析器有两个参数,分别表示的是前缀和后缀,意思就是,视图解析器会自动的帮你拼接url即: /WEB-INF/jsp/test.jsp, 那么现在就是一个完整的url了***
最后就会将结果渲染在视图上