1、SpringMVC框架
1.1、什么是SpringMVC?
SpringMVC是Spring框架的一个模块,SpringMVC和Spring无需通过中间整合层进行整合。
SpringMVC是一个基于mvc的web层框架。
1.2、mvc在b/s系统下的应用
mvc是一种设计模式,mvc在b/s系统下的应用如下图:
1.3、SpringMVC框架
原理图:
执行步骤:
第一步:发起请求到前端控制器(DispatcherServlet)
第二步:前端控制器请求处理器映射器(HandlerMapping)查找Handler,可以根据xml配置、注解进行查找。
第三步:处理器映射器(HandlerMapping)向前端控制器返回Handler(一个包含Handler的执行链)。
第四步:前端控制器调用处理器适配器去执行Handler
第五步:处理器适配器去执行Handler
第六步:Handler执行完成后给处理器适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回ModelAndView(SpringMVC的一个底层对象,包括Model和View)
第八步:前端控制器请求视图解析器(ViewResolver)去进行视图解析(根据逻辑视图名解析成真正的物理视图(jsp))
第九步:视图解析器向前段控制器返回View
第十步:前端控制器进行试图渲染,视图渲染将模型数据(在ModelAndView对象中)填充到request域
第十一步:前端控制器向用户响应结果
组件:
1、前端控制器DispatcherServlet(不需要程序员开发)
作用:接收请求、响应结果,相当于转发器,中央处理器。DispatcherServlet减少了其它组件之间的耦合度。
2、处理器映射器HandlerMapping(不需要程序员开发)
作用:根据请求的url查找Handler
3、处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
4、处理器Handler(需要程序员开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
5、视图解析器ViewResolver(不需要程序员开发)
作用:进行视图解析,根据逻辑视图名解析成真正的视图
6、视图View(需要程序员开发jsp)
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf……)
2、入门程序
2.1、需求
商品订单管理
功能需求:商品列表查询
2.2、环境准备
springmvc版本:spring3.2
需要spring3.2所有jar包(一定包括spring-webmvc-3.2.0.RELEASE.jar)
2.3、配置前端控制器
在web.xml中配置前端控制器
<!-- SpringMVC前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--
contextConfigLocation配置SpringMVC加載的配置文件(配置处理器映射器、适配器等)
如果不配置contextConfigLocation,默认加载的是/WEB-INF/servlert名称-servlet.xml(springmvc-servlet.xml)
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--
第一种:*.action,访问以.action结尾,由DispatcherServlet进行解析
第二种:/,所有访问的地址都由DispatcherServlet进行解析,对于静态文件的解析需要配置不让DispatcherServlet进行解析,
使用此种方式可以实现RESTful风格的url
第三种:/*,这样配置不对,使用这种方式配置,最终要转发到一个jsp页面,仍然会由DispatcherServlet解析jsp地址,不能根据jsp页面找到handler,会报错。
-->
<url-pattern>*.action</url-pattern>
</servlet-mapping>
2.4、配置处理器适配器
在classpath下的springmvc.xml中配置处理器适配器
<span style="white-space:pre"> </span><!--
处理器适配器:
所有的处理器适配器都实现HandlerAdapter接口
-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
通过查看源代码:
此适配器能执行实现Controller接口的Handler。
2.5、开发Handler
需要实现Controller,才能由org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter适配器执行。
package lsq.ssm.controller;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lsq.ssm.po.Items;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
/**
* 实现Controller接口的处理器
* @author Daniel Li
*
*/
public class ItemsController1 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
//调用service查找数据库,查询商品列表,这里使用静态数据模拟
List<Items> itemsList = new ArrayList<Items>();
//向itemsList中填充静态数据
Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
Items items_2 = new Items();
items_2.setName("苹果手机");
items_2.setPrice(5000f);
items_2.setDetail("iphone6苹果手机!");
itemsList.add(items_1);
itemsList.add(items_2);
//返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
//相当于request的setAttribute(),在jsp页面中通过itemsList获取数据
modelAndView.addObject("itemsList", itemsList);
//指定视图
modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
return modelAndView;
}
}
2.6、视图编写
2.7、配置Handler
为了编写的Handler能够在spring容器中加载。
<!-- 配置Handler -->
<bean name="/queryItems.action" class="lsq.ssm.controller.ItemsController1"/>
2.8、配置处理器映射器
在classpath下的springmvc.xml中配置处理器映射器
<!--
处理器映射器:
将bean的name作为url进行查找,需要在配置Handler时指定beanname(就是url)
所有的映射器都实现HandlerMapping接口
-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
2.9、配置视图解析器
需要配置解析jsp的视图解析器
<!--
视图解析器:
解析jsp视图,默认使用jstl标签,classpath下要有jstl的包
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
2.10、部署调试
访问地址:http://localhost:8080/springmvc_day1/queryItems.action
2.11、两种常见错误
处理器映射器根据url找不到Handler,报下边的错误。说明url错误。
处理器映射器根据url找到了Handler,转发的jsp页面找不到,报下边的错误,说明jsp页面地址写错了。
3、非注解的处理器映射器和处理器适配器
3.1、非注解的处理器映射器
处理器映射器:
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
另一个映射器:
org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
<!-- 简单url映射 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- 对itemsController1进行url映射,url是/queryItems1.action -->
<prop key="/queryItems1.action">itemController1</prop>
<prop key="/queryItems2.action">itemController1</prop>
</props>
</property>
</bean>
修改Handler配置,添加id属性:
<!-- 配置Handler -->
<bean id="itemController1" name="/queryItems.action" class="lsq.ssm.controller.ItemsController1"/>
☆结论:多个映射器可以并存,前端控制器判断url能让哪些映射器映射,就让正确的映射器处理。
3.2、非注解的处理器适配器
第一种:
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
要求编写的Handler实现Controller接口。
第二种:
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
要求编写的Handler实现HttpRequestHandler接口。
package lsq.ssm.controller;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lsq.ssm.po.Items;
import org.springframework.web.HttpRequestHandler;
/**
* 实现HttpRequestHander接口的处理器
* @author Daniel Li
*
*/
public class ItemsController2 implements HttpRequestHandler{
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse resposne)
throws ServletException, IOException {
//调用service查找 数据库,查询商品列表,这里使用静态数据模拟
List<Items> itemsList = new ArrayList<Items>();
//向list中填充静态数据
Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
Items items_2 = new Items();
items_2.setName("苹果手机");
items_2.setPrice(5000f);
items_2.setDetail("iphone6苹果手机!");
itemsList.add(items_1);
itemsList.add(items_2);
//设置模型数据
request.setAttribute("itemsList", itemsList);
//设置转发的视图
request.getRequestDispatcher("/WEB-INF/jsp/items/itemsList.jsp").forward(request, resposne);
//使用此方法可以通过修改response,设置响应的数据格式,比如响应json数据
/*response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");*/
}
}
配置Handler:
<!-- 配置另一个Handler -->
<bean id="itemController2" class="lsq.ssm.controller.ItemsController2"/>
配置处理器映射器:
<!-- 另一个非注解的适配器HttpRequestHandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
DispatcherServlet.properties文件中的内容如下:
前端控制器从上边的文件中加载处理器映射器、适配器、视图解析器等组件,如果不在springmvc.xml中进行配置,就使用默认加载的。
5、注解的处理器映射器和适配器
在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping注解映射器。
在spring3.1之后使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping注解映射器。
在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter注解适配器。
在spring3.1之后使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter注解适配器。
5.1、配置注解映射器和适配器
<!--注解映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<!-- 使用 mvc:annotation-driven代替上边注解映射器和注解适配器配置
mvc:annotation-driven默认加载很多的参数绑定方法,
比如json转换解析器就默认加载了,如果使用mvc:annotation-driven不用配置上边的RequestMappingHandlerMapping和RequestMappingHandlerAdapter
实际开发时使用mvc:annotation-driven
-->
<!-- <mvc:annotation-driven></mvc:annotation-driven> -->
5.2、开发注解Handler
使用注解的映射器和注解的适配器。(☆:注解的映射器和注解的适配器必须配对使用)
package lsq.ssm.controller;
import java.util.ArrayList;
import java.util.List;
import lsq.ssm.po.Items;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* 注解开发的Handler
* @author Daniel Li
*
*/
//使用Controller标识 它是一个控制器
@Controller
public class ItemsController3 {
//商品查询列表
//@RequestMapping实现 对queryItems方法和url进行映射,一个方法对应一个url
//一般建议将url和方法写成一样
@RequestMapping("/queryItems")
public ModelAndView queryItems()throws Exception{
//调用service查找 数据库,查询商品列表,这里使用静态数据模拟
List<Items> itemsList = new ArrayList<Items>();
//向list中填充静态数据
Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
Items items_2 = new Items();
items_2.setName("苹果手机");
items_2.setPrice(5000f);
items_2.setDetail("iphone6苹果手机!");
itemsList.add(items_1);
itemsList.add(items_2);
//返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
//相当 于request的setAttribut,在jsp页面中通过itemsList取数据
modelAndView.addObject("itemsList", itemsList);
//指定视图
modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
return modelAndView;
}
}
5.3、在spring容器中加载Handler
<!-- 对于注解的Handler可以单个配置
实际开发中建议使用组件扫描
-->
<!-- <bean class="lsq.ssm.controller.ItemsController3" /> -->
<!-- 可以扫描controller、service、...
这里让扫描controller,指定controller的包
-->
<context:component-scan base-package="lsq.ssm.controller"></context:component-scan>
5.4、部署调试
访问:http://localhost:8080/springmvc_day1/queryItems.action
6、源码分析
通过前端控制器源码分析SpringMVC的执行流程。
第一步:前端控制器接收请求
调用doDispatch
第二步:前端控制器调用处理器映射器查找Handler
点击该方法进去:
第三步:调用处理器适配器执行Handler,得到执行结果ModelAndView
第四步:视图渲染,将model数据填充到request域。
视图解析,得到view:
点击render方法进去:
调用view的渲染方法,将model数据填充到request域:
渲染方法:
将model数据填充到request域: