一、SpringMVC原理解析
1、我们首先分析一下整个请求处理的流程:
①在B/S架构的系统中,用户首先从浏览器中发出Http请求(请求中会包含用户的请求内容信息或者表单信息),然后首先经过前端控制器(DispatcherServlet)进行处理,
②然后前端控制器需要接触处理器映射器知道自己使用哪一个处理器处理请求信息,
③然后处理器映射器会返回给前端控制器一个处理器执行链,
④前端控制器通过处理器适配器去执行处理器,然后让处理器适配器返回给自己模型和视图,
⑤处理器适配器去调用相应的处理器
⑥执行后的处理器返回给处理器适配器信息,具体就是返回处理结果(ModelAndView)
⑦处理器适配器得到模型视图(ModelAndView)之后,将之返回给前端控制器
⑧前端控制器自己本身不对ModelAndView进行解析,而是交给视图解析器进行视图解析
⑨视图解析器完成视图解析后,将视图(View)返回给前端控制器
⑩前端控制器得到view后,会交给视图进行渲染,具体就是jsp、freemaker等等,最后响应给用户
2、通过上面的解释和线面图例的理解,我们可以对SpringMVC这个框架的处理流程有一个大致的了解。上面只是介绍了一部分组件,我们下面可以简单的介绍各个组件的功能
①前端控制器DispatcherServlet:作为整个SpringMVC的中央处理器,可以发现整个流程中大部分都经过它。用户请求首先到达前端处理器(MVC模式中C层),作为整个流程的中心,由他调用其他组件,其存在大大降低了各个组件的耦合性
②处理器映射器HandlerMapping:顾名思义,处理器映射器就是根据用户请求找到相应的处理器Handler进行处理请求,SpringMVC中提供配置文件方式、接口方式、注解方式等等实现不同的映射方式
③处理器适配器HandlerAdapter:不同于处理器映射器,处理器适配器的作用是对处理器进行执行(处理器映射器是找到处理器),HandlerAdapter可以通过扩展适配器对多种类型的适配器进行执行
④处理器Handler:处理器也可以说是后端控制器,需要由自己根据处理器适配器的规范来进行编写,在DispatcherServlet的控制下对具体的用户请求进行处理
⑤视图解析器ViewResolver:负责将结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jsp、freemarker、pdf等。
二、搭建SpringMVC程序
1、首先我们需要知道SpringMVC是Spring的一个部分,所以在编写程序开始的时候需要导入SpringMVC的jar包
2、在导入springmvc的相关jar包之后,需要在web.xml中配置前端控制器DispatcherServlet,在配置前端控制器的时候,我们自己需要手动修改配置springmvc的配置文件以及他的路径
下面就是在web.xml中配置到的前端控制器
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 5 version="4.0"> 6 <!--配置前端控制器--> 7 <servlet> 8 <servlet-name>SpringMvc</servlet-name> 9 <servlet-class> 10 org.springframework.web.servlet.DispatcherServlet 11 </servlet-class> 12 <!-- 13 配饰SpringMVC的配置文件(处理器映射器、适配器等) 14 注明需要这样配置的原因:自己配置contextConfigLocation,就不会自己默认加载/WEB-INF/下面的dispatch-servlet.xml 15 --> 16 <init-param> 17 <param-name>contextConfigLocation</param-name> 18 <param-value>classpath:springmvc.xml</param-value> 19 </init-param> 20 </servlet> 21 <servlet-mapping> 22 <servlet-name>SpringMvc</servlet-name> 23 <url-pattern>*.do</url-pattern> 24 </servlet-mapping> 25 </web-app>
3、下面说明一下上面配置的url-pattern的问题,在SpringMVC中,DispatcherServlet的拦截方式有下面两种
①*.do、*.action:表示拦截指定后缀的url,这种方式对于服务器端的静态资源(jsp、css、image等)不会拦截
②/ :表示拦截所有资源,这种拦截方式的设计可以实现RESTful风格,后面会介绍到
需要注意的是:不能使用/*(这种方式下,当请求到action后,action处理完返回ModelAndView的jsp信息时,又会被拦截,导致不能根据jsp映射成功)
4、我们上面修改了SpringMVC的配置文件,所以我们下来需要自己修改SpringMVC的配置文件。而在springmvc.xml中,我们需要配置处理器映射器,处理器(Handler),处理器适配器、视图解析器
①配置处理器映射器,处理器映射器会根据配置的beanname找到相应的URL,找到的就是制定的Handler,然后交给Handler进行处理
1 <!-- 2 处理器映射器 3 将bean的NAME作为url进行查找,需要配置handler的时候指定bean的NAME(即url) 4 --> 5 <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
②配置处理器适配器,我们配置的是SimpleControllerHandlerAdapter,查看该类的源代码,会发现下面这个方法,这个方法就是判断我们自己编写的处理器(Handler)是否满足条件(实现Controller接口),所以在接下来编写Handler时需要实现Controller接口以及其中的方法
下面这是处理器适配器的配置
1 <!-- 2 处理器适配器 3 所有处理器适配器都实现了Handler Adapter这个接口,通过观察SimpleControllerHandlerAdapter中的support方法可以发现, 4 我们自己需要实现Controller接口 才能执行 5 --> 6 <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
③根据上面讲的,我们就需要自己编写Handler,我们先查看一下Controller接口的代码,发现Controller只有一个方法,即请求处理然后返回ModelAndView对象
所以下来我们就自己实现这个方法,然后返回ModelAndView(包括其中的数据,和路径信息):
1 package cn.test.springmvc.controller; 2 3 import cn.test.springmvc.po.Product; 4 import org.springframework.web.servlet.ModelAndView; 5 import org.springframework.web.servlet.mvc.Controller; 6 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 import java.util.ArrayList; 10 import java.util.List; 11 12 /** 13 * 实现Controller的Handler 14 */ 15 public class ItemController implements Controller { 16 17 @Override 18 public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { 19 20 //模拟数据 21 List<Product> products = new ArrayList<>(); 22 23 Product product1 = new Product(); 24 product1.setPname("笔记本"); 25 product1.setShop_price(123); 26 products.add(product1); 27 28 Product product2 = new Product(); 29 product2.setPname("手机"); 30 product2.setShop_price(123); 31 products.add(product2); 32 33 //返回ModelAndView 34 ModelAndView modelAndView = new ModelAndView(); 35 //想模型视图中添加数据 36 modelAndView.addObject("products", products); 37 38 //指定视图 39 modelAndView.setViewName("/WEB-INF/items/itemsList.jsp"); 40 return modelAndView; 41 } 42 }
我们自己编写好Handler之后,就需要根据处理器映射器的要求,在springmvc.xml中配置Handler
1 <!--配置Handler--> 2 <bean name="/queryItemList.do" class="cn.test.springmvc.controller.ItemController"></bean>
配置的beanname就会处理器映射器进行映射,然后执行相应的处理器
④上面我们返回的是jsp页面信息,所以下俩就需要配置视图解析器,解析jsp。
1 <!--视图解析器--> 2 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
我们来看一下InternalResourceViewResolver这个类中的代码,该类默认支持jstl解析,所以我们就导入jstl的jar包,正好解释了前面第一步中导包(其中含有jstl包)
private static final boolean jstlPresent = ClassUtils.isPresent("javax.servlet.jsp.jstl.core.Config", InternalResourceViewResolver.class.getClassLoader());
⑤在上面的Handler中,我们返回了一个jsp页面,下面就简单的根据返回信息编写一张简单的jsp页面

1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 4 <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> 5 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 6 <html> 7 <head> 8 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 9 <title>查询商品列表</title> 10 </head> 11 <body> 12 <form action="${pageContext.request.contextPath }/item/queryItem.action" method="post"> 13 查询条件: 14 <table width="100%" border=1> 15 <tr> 16 <td><input type="submit" value="查询"/></td> 17 </tr> 18 </table> 19 商品列表: 20 <table width="100%" border=1> 21 <tr> 22 <td>商品名称</td> 23 <td>商品价格</td> 24 <td>操作</td> 25 </tr> 26 <c:forEach items="${products }" var="item"> 27 <tr> 28 <td>${item.pname }</td> 29 <td>${item.shop_price }</td> 30 31 <td><a href="${pageContext.request.contextPath }/item/editItem.do?id=${item.pid}">修改</a></td> 32 33 </tr> 34 </c:forEach> 35 36 </table> 37 </form> 38 </body> 39 40 </html>
⑥然后在IDEA中部署Tomcat,进行测试