首页 > 代码库 > SpringMVC入门
SpringMVC入门
SpringMVC框架
什么是springmvc?
- Spring web mvc和Struts2都属于表现层的框架,它是Spring框架的一部分,我们可以从Spring的整体结构中看得出来:
- springmvc和spring无需通过中间整合层进行整合。
- springmvc是一个基于mvc的web框架。
Web MVC
mvc设计模式在b/s系统下应用:
- 我们现在站在框架角度思考MVC!!
还记得以前我们学习的Struts2吗??如果我们现在站在框架角度思考MVC,Filter就是我们的控制器,而Action就是我们的Model,JSP等视图显示技术当然还是我们的View。但是往往我们开发的时候却是站在网站角度,JSP等显示技术是我们的视图层,Service层和Dao层是我们的Model层,而Action是我们的控制层,而这个时候的Action也被叫做后端控制器。其实不管怎么想,这都是MVC架构思想。
springmvc框架
执行过程解说:
第一步:发起请求到前端控制器(DispatcherServlet)
第二步:前端控制器请求HandlerMapping查找 Handler
- 可以根据xml配置、注解进行查找
第三步:处理器映射器HandlerMapping向前端控制器返回Handler
第四步:前端控制器调用处理器适配器去执行Handler
第五步:处理器适配器去执行Handler
第六步:Handler执行完成给适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回ModelAndView
- ModelAndView是springmvc框架的一个底层对象,包括 Model和view
第八步:前端控制器请求视图解析器去进行视图解析
- 根据逻辑视图名解析成真正的视图(jsp)
第九步:视图解析器向前端控制器返回View
第十步:前端控制器进行视图渲染
- 视图渲染将模型数据(在ModelAndView对象中)填充到request域
第十一步:前端控制器向用户响应结果
组件:
1、前端控制器DispatcherServlet(一般不需要程序员开发,但是架构师级别有可能去继承DispatcherServlet去写一些特殊的功能)
作用接收请求,响应结果,相当于转发器,中央处理器。有了DispatcherServlet减少了其它组件之间的耦合度。
2、处理器映射器HandlerMapping(不需要程序员开发)
- 作用:根据请求的url查找Handler
- HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3、处理器适配器HandlerAdapter(不需要程序员开发)
- 作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler,这里的Handler必须实现Controller接口,才是一个Handler。
- 通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
4、处理器Handler(需要程序员开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
5、视图解析器View resolver(不需要程序员开发)
- 作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
- View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。
6、视图View(需要程序员开发jsp)
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)
入门程序
需求
以案例作为驱动。
功能需求:商品列表查询
环境准备
Spring4.3.7的jar包下载地址(已经包含SpringMVC)
老师用的完整包图
Spring常用包的介绍
配置前端控制器
在web.xml中配置前端控制器。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>SpringMVC</display-name>
<!-- SpringMVC前端控制器 -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation配置SpringMVC加载的配置文件(配置处理器映射器、适配器等等)
如果不配置contextConfigLocation,默认加载的是/WEB-INF/servlet名称-servlet.xml(SpringMVC-servlet.xml)
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<!--
第一种:*.action,访问以.action结尾由DispatcherServlet进行解析
第二种:/,所以访问的地址由DispatcherServlet进行解析,对于静态文件的解析需要配置不让DispatcherServlet进行解析,对于静态文件的解析需要配置,不让DispatcherServlet进行解析。
使用此种方式可以实现 RESTful 风格的url 。
第三种:/*,这样配置不对,使用这种配置,最终要转发到一个jsp页面时,仍然会由DispatcherServlet解析jsp地址,不能根据jsp页面找到Handler,会报错。
个人感觉这种拦截方式的实现和当前Servlet实现方式有关,因为这三种拦截方式和我们JavaWeb初期学习的三种拦截方式有出入。
-->
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
配置处理器适配器
- 在classpath下的springmvc.xml中配置处理器适配器
- SimpleControllerHandlerAdapter:即简单控制器处理适配器,所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean作为
Springmvc的后端控制器。
<!-- 处理器适配器
所有处理器适配器都实现HandlerAdapter接口
-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
通过查看源代码:
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
此适配器能执行实现Controller接口的Handler。
编写视图
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP ‘itemsList.jsp‘ starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
<!-- 这里使用的requestScope读取数据成功,就证明了我们的数据是放在requestScope里面的 -->
<h3>欢迎来到首页</h3>
<c:forEach items="${requestScope.itemsList }" var="item">
<p>商品名字=${item.name}---商品价格=${item.price }---生产日期=<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>---描述=${item.detail }</p>
</c:forEach>
</body>
</html>
开发Handler
需要实现 controller
接口,才能由org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
适配器执行。
public class ItemController implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
/*
* 调用service查找数据库,查询商品列表,这里使用静态数据模拟。
*/
List<Item> items=new ArrayList<Item>();
items.add(new Item("FireLang", 456.65, "技匠", null, new Date()));
//创建ModelAndView
ModelAndView modelAndView=new ModelAndView();
//相当于 request 的 setAttribut,在jsp页面通过itemsList获取数据。
modelAndView.addObject("itemsList", items);
//指定跳转视图
//为了安全起见(必须在我们的允许范围内访问视图),所以我们把视图放在了WEB-INF目录下。
modelAndView.setViewName("/WEB-INF/content/itemsList.jsp");
return modelAndView;
}
}
配置Handler
让我们编写的Handler在Spring容器中加载。(因为SpringMVC是Spring的一个子模块,所以Handler的bean加载就放在springmvc.xml核心配置文件里面)
<!-- 配置Handler -->
<bean name="/showItemsList.action" class="cn.domarvel.controller.ItemController"></bean>
配置处理器映射器
在classpath下的springmvc.xml中配置处理器映射器
<!-- 处理器映射器
将bean的name作为url进行查找,需要在配置Handler时指定beanname(就是url)
-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
配置视图解析器
需要配置解析jsp的视图解析器。
<!-- 视图解析器
解析JSP,默认使用JSTL标签,classpath下得有JSTL包
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
对于视图解析器讲解一个扩展使用方法:
<!-- ViewResolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
InternalResourceViewResolver:支持JSP视图解析
viewClass:JstlView表示JSP模板页面需要使用JSTL标签库,所以classpath中必须包含jstl的相关jar 包;
prefix 和suffix:查找视图页面的前缀和后缀,最终视图的址为:
前缀+逻辑视图名+后缀,逻辑视图名需要在controller中返回ModelAndView指定,比如逻辑视图名为hello,则最终返回的jsp视图地址 “WEB-INF/jsp/hello.jsp”
SpringMVC整体配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!-- 处理器映射器
将bean的name作为url进行查找,需要在配置Handler时指定beanname(就是url)
-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- 配置Handler -->
<bean id="itemsListId" name="/showItemsList.action" class="cn.domarvel.controller.ItemController"></bean>
<!-- 处理器适配器
所有处理器适配器都实现HandlerAdapter接口
-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- 视图解析器
解析JSP,默认使用JSTL标签,classpath下得有JSTL包
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
</beans>
tips:常常我们开发的时候都是启用DEBUG模式进行开发!!
部署调试
处理器映射器根据url找不到Handler,报下边的错误。说明url错误。
处理器映射器根据url找到了Handler,转发的jsp页面找到,报下边的错误,说明jsp页面地址错误了。
非注解的处理器映射器和适配器
处理器映射器部分
DispatcherServlet
DispathcerServlet作为springmvc的中央调度器存在,DispatcherServlet创建时会默认从DispatcherServlet.properties文件加载springmvc所用的各各组件,如果在springmvc.xml中配置了组件则以springmvc.xml中配置的为准,DispatcherServlet的存在降低了springmvc各各组件之间的耦合度。
在DispatcherServlet.properties里面你可以看到:
# Default implementation classes for DispatcherServlet‘s strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
//默认配置的处理器映射器,一个是按照bean的name作为url查找,一个是注解
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping, org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
//默认配置了两个适配器,一个是要实现Controller接口的适配器,一个是要实现HttpRequestHandler接口的适配器。当然还有注解方法。
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter, org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter, org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver, org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver, org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
所以我们的非注解程序开发中,在springmvc.xml中我们不用配置处理器映射器和处理器适配器就能够正常运行程序。只需要配置处理器的bean标签,配置name属性值作为url就行了。
HandlerMapping处理器映射器
HandlerMapping 负责根据request请求找到对应的Handler处理器及Interceptor拦截器,将它们封装在HandlerExecutionChain 对象中给前端控制器返回。处理器映射器(BeanNameUrlHandlerMapping,SimpleUrlHandlerMapping)都要实现HandlerMapping接口。
BeanNameUrlHandlerMapping
BeanNameUrl处理器映射器,根据请求的url与spring容器中定义的bean的name进行匹配,从而从spring容器中找到bean实例。
<!-- 处理器映射器
将bean的name作为url进行查找,需要在配置Handler时指定beanname(就是url)
-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
SimpleUrlHandlerMapping
simpleUrlHandlerMapping是BeanNameUrlHandlerMapping的增强版本,它可以将url和处理器bean的id进行统一映射配置。
<!-- 简单url映射 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- 对itemsListId进行url映射,url是/showItemsList1.action -->
<!-- 对同一个Handler后端处理器可以配置多个url进行解析 -->
<!-- 多个映射处理器类可以共存,并且可以写相同的url -->
<prop key="/showItemsList1.action">itemsListId</prop>
<prop key="/showItemsList2.action">itemsListId</prop>
<prop key="/showItemsList.action">itemsListId</prop>
</props>
</property>
</bean>
- 多个映射器可以并存,前端控制器判断url能让哪些映射器映射,就让正确的映射器处理。
处理器适配器部分
HandlerAdapter处理器适配器
HandlerAdapter会根据适配器接口对后端控制器进行包装(适配),包装后即可对处理器进行执行,通过扩展处理器适配器可以执行多种类型的处理器,这里使用了适配器设计模式。处理器适配器都要实现HandlerAdapter接口。
SimpleControllerHandlerAdapter
SimpleControllerHandlerAdapter简单控制器处理器适配器,所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean通过此适配器进行适配、执行。
适配器配置如下:
<!-- 处理器适配器
所有处理器适配器都实现HandlerAdapter接口
-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
HttpRequestHandlerAdapter
HttpRequestHandlerAdapter,http请求处理器适配器,所有实现了org.springframework.web.HttpRequestHandler 接口的Bean通过此适配器进行适配、执行。
适配器配置如下:
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
Controller实现如下:
public class ItemListController implements HttpRequestHandler{
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 调用service查找数据库,查询商品列表,这里使用静态数据模拟。
*/
List<Item> items=new ArrayList<Item>();
items.add(new Item("FireLang", 456.65, "技匠", null, new Date()));
request.setAttribute("itemsList", items);
request.getRequestDispatcher("/WEB-INF/content/itemsList.jsp").forward(request, response);
}
}
注意:因为这是创建的一个新的Hander,所以我们必须要在springmvc.xml核心配置文件里面创建该Handler的bean对象。
从上边可以看出此适配器器的handleRequest方法没有返回ModelAndView,可通过response修改定义响应内容,比如返回json数据:
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");
目前springmvc.xml整体文件配置如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!-- 处理器映射器
将bean的name作为url进行查找,需要在配置Handler时指定beanname(就是url)
-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- 简单url映射 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- 对itemsListId进行url映射,url是/showItemsList1.action -->
<!-- 对同一个Handler后端处理器可以配置多个url进行解析 -->
<!-- 多个映射处理器类可以共存,并且可以写相同的url -->
<prop key="/showItemsList1.action">itemsListId</prop>
<prop key="/showItemsList2.action">itemsListId</prop>
<prop key="/showItemsList.action">itemsListId</prop>
</props>
</property>
</bean>
<!-- 配置Handler -->
<bean id="itemsListId" name="/showItemsList.action" class="cn.domarvel.controller.ItemController"></bean>
<!-- 配置ItemListController-HttpHandler -->
<bean id="itemsListId-httpAdapter" name="/showItemsList-httpAdapter.action" class="cn.domarvel.controller.ItemListController"></bean>
<!-- 处理器适配器
所有处理器适配器都实现HandlerAdapter接口
-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- 配置HttpRequestHandlerAdapter适配器 -->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
<!-- 视图解析器
解析JSP,默认使用JSTL标签,classpath下得有JSTL包
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
</beans>
总结:
对于多个处理器映射器和多个处理器适配器是可以共存的!!
因为一个处理器可能只有某个适配器才能够执行,并且一个处理器只有某个处理器映射器能够找到!!
SpringMVC注解开发
SpringMVC入门