首页 > 代码库 > 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注解开发

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    SpringMVC入门