SpringMVC

http://dblab.xmu.edu.cn/blog/2204-2/

1 SpringMVC架构

在这里插入图片描述

  1. 用户发送请求至前端控制器DispatcherServlet
  2. DispatcherServlet收到请求调用一个或多个HandlerMapping处理器映射器。
  3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
  4. DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
  5. 执行处理器Handler(Controller,也叫后端控制器)。
  6. Controller执行完成返回ModelAndView
  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
  8. DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图
  9. ViewReslover解析后返回具体View
  10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
  11. DispatcherServlet响应用户

1.1组件说明

DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。

HandlerMapping:处理器映射器
HandlerMapping负责根据用户请求url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

HandlAdapter:处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。(就像USB转换接口)

Handler:处理器
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理(相当于controller层的action)。由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。

ViewResolver:视图解析器
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。

View:视图
springmvc框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

2 入门程序搭建

2.1永远的HelloWorld

1) 新建Web工程,加入 jar 包

spring-aop-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
commons-logging-1.1.3.jar
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar

2) 在 web.xml 中配置 DispatcherServlet

<!-- 配置SpringMVC核心控制器: -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置DispatcherServlet的初始化參數:设置文件的路径和文件名称 -->
<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>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

① 解释配置文件的名称定义规则:
实际上也可以不通过 contextConfigLocation 来配置 SpringMVC 的配置文件, 而使用默认的.默认的配置文件为: /WEB-INF/-servlet.xml
3) 加入 Spring MVC 的配置文件:springmvc.xml
① 增加名称空间
② 增加配置

<!-- 设置扫描组件的包: -->
<context:component-scan base-package="com.atguigu.springmvc"/>
 
<!-- 配置映射解析器:如何将控制器返回的结果字符串,转换为一个物理的视图文件-->
<bean id="internalResourceViewResolver" 
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>

4) 需要创建一个入口页面,index.jsp

<a href="${pageContext.request.contextPath }/helloworld">Hello World</a>

5) 编写处理请求的处理器,并标识为处理器

    package com.atguigu.springmvc.controller;
     
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
     
    @Controller  //声明Bean对象,为一个控制器组件
    public class HelloWorldController {
     
    /**
     * 映射请求的名称:用于客户端请求;类似Struts2中action映射配置的action名称
     * 1. 使用 @RequestMapping 注解来映射请求的 URL
     * 2. 返回值会通过视图解析器解析为实际的物理视图, 对于 InternalResourceViewResolver 视图解析器, 
     * 会做如下的解析:
     *                 通过 prefix + returnVal + suffix 这样的方式得到实际的物理视图, 然后做转发操作.
     *                 /WEB-INF/views/success.jsp
     */
    @RequestMapping(value="/helloworld",method=RequestMethod.GET)
    public String helloworld(){
         System.out.println("hello,world");
         return "success"; //结果如何跳转呢?需要配置映射解析器
    }        
    }

6) 编写视图

/WEB-INF/views/success.jsp
<h4>Sucess Page</h4>

7) 部署测试:

http://localhost:8080/SpringMVC_01_HelloWorld/index.jsp

在这里插入图片描述

3 @RequestMapping注解

2.1 @RequestMapping 映射请求注解

2.1.1 @RequestMapping 概念

1) SpringMVC使用@RequestMapping注解为控制器指定可以处理哪些 URL 请求
2) 在控制器的类定义及方法定义处都可标注 @RequestMapping
① 标记在类上:提供初步的请求映射信息。相对于 WEB 应用的根目录
② 标记在方法上:提供进一步的细分映射信息。相对于标记在类上的 URL。
3) 若类上未标注 @RequestMapping,则方法处标记的 URL 相对于 WEB 应用的根目录
4) 作用:DispatcherServlet 截获请求后,就通过控制器上 @RequestMapping 提供的映射信息确定请求所对应的处理方法

  • @RequestMapping 除了可以使用请求 URL 映射请求外,还可以使用请求方法、请求参数及请求头映射请求
  • @RequestMapping 的 value【重点】、method【重点】、params【了解】 及 heads【了解】 分别表示请求 URL、请求方法、请求参数及请求头的映射条件,他们之间是与的关系,联合使用多个条件可让请求映射更加精确化。

2.1.2 映射请求占位符@PathVariable

带占位符的 URL 是 Spring3.0 新增的功能,该功能在 SpringMVC 向 REST 目标挺进发展过程中具有里程碑的意义
通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:
URL 中的 {xxx} 占位符可以通过 @PathVariable("xxx") 绑定到操作方法的入参中

实验代码
1) 定义控制器方法

//@PathVariable 注解可以将请求URL路径中的请求参数,传递到处理请求方法的入参中
@RequestMapping(value="/testPathVariable/{id}")
public String testPathVariable( @PathVariable("id") Integer id ){
System.out.println("testPathVariable...id="+id);
return "success";
}

2) 请求链接

<!-- 测试 @PathVariable -->
<a href="springmvc/testPathVariable/1">testPathVariable</a>

4 处理请求数据

4.1请求处理方法签名

1) Spring MVC 通过分析处理方法的签名,HTTP请求信息绑定到处理方法的相应入参中。
2) Spring MVC 对控制器处理方法签名的限制是很宽松的,几乎可以按喜欢的任何方式对方法进行签名。
3) 必要时可以对方法及方法入参标注相应的注解( @PathVariable 、@RequestParam、@RequestHeader 等)、
4) Spring MVC 框架会将 HTTP 请求的信息绑定到相应的方法入参中,并根据方法的返回值类型做出相应的后续处理。

4.2 @RequestParam注解

1)在处理方法入参处使用 @RequestParam 可以把请求参数传递给请求方法
2)value:参数名
3)required:是否必须。默认为 true, 表示请求参数中必须包含对应的参数,若不存在,将抛出异常
4)defaultValue: 默认值,当没有传递参数时使用该值

实验代码
1) 增加控制器方法

/**
 * @RequestParam 注解用于映射请求参数
 */
@RequestMapping(value="/testRequestParam")
public String testRequestParam(
@RequestParam(value="username") String username,
@RequestParam(value="age",required=false,defaultValue="0") int age){
System.out.println("testRequestParam - username="+username +",age="+age);
return "success";
}

2) 增加页面链接

<!--测试 请求参数 @RequestParam 注解使用 -->
<a href="springmvc/testRequestParam?username=atguigu&age=10">testRequestParam</a>

4.3 @RequestHeader 注解

1) 使用 @RequestHeader 绑定请求报头的属性值
2) 请求头包含了若干个属性,服务器可据此获知客户端的信息,通过 @RequestHeader 即可将请求头中的属性值绑定到处理方法的入参中

4.4 @CookieValue 注解

1) 使用 @CookieValue 绑定请求中的 Cookie 值
2) @CookieValue 可让处理方法入参绑定某个 Cookie 值

4.5 使用POJO作为参数

1) 使用 POJO 对象绑定请求参数值
2) Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值。支持级联属性。如:dept.deptId、dept.address.tel 等

4.6 使用Servlet原生API作为参数

MVC 的 Handler 方法可以接受哪些 ServletAPI 类型的参数

  1. HttpServletRequest
  2. HttpServletResponse
  3. HttpSession
  4. java.security.Principal
  5. Locale
  6. InputStream
  7. OutputStream
  8. Reader
  9. Writer

5 处理响应数据

5.1 SpringMVC 输出模型数据概述

1) ModelAndView: 处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据
2) Map 及 Model: 入参为 org.springframework.ui.Model、org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中

5.2处理模型数据之 ModelAndView

1)控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数据信息
2)添加模型数据:

MoelAndView addObject(String attributeName, Object attributeValue)
ModelAndView addAllObject(Map<String, ?> modelMap)

3)设置视图:

void setView(View view)
void setViewName(String viewName)

实验代码
1) 增加控制器方法

/**
 * 目标方法的返回类型可以是ModelAndView类型
 *                 其中包含视图信息和模型数据信息
 */
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
System.out.println("testModelAndView");
String viewName = "success";
ModelAndView mv = new ModelAndView(viewName );
mv.addObject("time",new Date().toString());        //实质上存放到request域中 
return mv;
}

2) 增加页面链接

<!--测试 ModelAndView 作为处理返回结果 -->
<a href="springmvc/testModelAndView">testModelAndView</a>

3) 增加成功页面,显示数据

time: ${requestScope.time }

5.3 处理模型数据之 Map

1)Spring MVC 在内部使用了一个 org.springframework.ui.Model 接口存储模型数据
具体使用步骤
2)Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器
3)如果方法的入参为 Map 或 Model 类型,Spring MVC 会将隐含模型的引用传递给这些入参。
4)在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据

实验代码
1) 增加控制器方法

    //目标方法的返回类型也可以是一个Map类型参数(也可以是Model,或ModelMap类型)
    @RequestMapping("/testMap")
    public String testMap(Map<String,Object> map){      //【【【重点】】】
    		System.out.println(map.getClass().getName());
  	  		//org.springframework.validation.support.BindingAwareModelMap
  			 map.put("names", Arrays.asList("Tom","Jerry","Kite"));
  			 return "success";
    }

2) 增加页面链接

<!-- 测试 Map 作为处理返回结果 -->
<a href="springmvc/testMap">testMap</a>

3) 增加成功页面,显示结果

names: ${requestScope.names }

4) 注意问题:**Map集合的泛型,key为String,Value为Object,**而不是String

6 视图解析

6.1 SpringMVC如何解析视图概述

1) 不论控制器返回一个String,ModelAndView,View 都会转换为ModelAndView对象,由视图解析器解析视图,然后,进行页面的跳转。
在这里插入图片描述

6.2 视图和视图解析器

1) 请求处理方法执行完成后,最终返回一个 ModelAndView 对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个 ModelAndView 对象,它包含了逻辑名和模型对象的视图
2) Spring MVC 借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是 JSP ,也可能是 Excel、JFreeChart等各种表现形式的视图
3) 对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现 MVC 的充分解耦

6.3 视图

1) 视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户,主要就是完成转发或者是重定向的操作.
2) 为了实现视图模型和具体实现技术的解耦,Spring 在 org.springframework.web.servlet 包中定义了一个高度抽象的 View 接口
3) 视图对象由视图解析器负责实例化。由于视图是无状态的,所以他们不会有线程安全的问题

6.4 视图解析器

1) SpringMVC 为逻辑视图名的解析提供了不同的策略,可以在 Spring WEB 上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一个具体的视图解析器实现类。
2) 视图解析器的作用比较单一:将逻辑视图解析为一个具体的视图对象。
3) 所有的视图解析器都必须实现 ViewResolver 接口
在这里插入图片描述
1) 程序员可以选择一种视图解析器或混用多种视图解析器
2) 每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性,可以通过 order 属性指定解析器的优先顺序,order 越小优先级越高。
3) SpringMVC 会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则将抛出 ServletException 异常
4) InternalResourceViewResolver

  • JSP 是最常见的视图技术,可以使用 InternalResourceViewResolve作为视图解析器:
    在这里插入图片描述

6.5重定向

1) 关于重定向
① 一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理
② 如果返回的字符串中带 forward:redirect: 前缀时,SpringMVC 会对他们进行特殊处理:将 forward: 和 redirect: 当成指示符,其后的字符串作为 URL 来处理
redirect:success.jsp:会完成一个到 success.jsp 的重定向的操作
forward:success.jsp:会完成一个到 success.jsp 的转发操作
2) 定义页面链接

<a href="springmvc/testRedirect">testRedirect</a>

3) 定义控制器方法

@RequestMapping("/testRedirect")
public String testRedirect(){
System.out.println("testRedirect");
return "redirect:/index.jsp";
//return "forward:/index.jsp";
}

使用Spring的表单标签

1) 通过 SpringMVC 的表单标签可以实现将模型数据中的属性和 HTML 表单元素相绑定,以实现表单数据更便捷编辑和表单值的回显
2) form 标签
 一般情况下,通过 GET 请求获取表单页面,而通过 POST 请求提交表单页面,因此获取表单页面和提交表单页面的 URL 是相同的。
 只要满足该最佳条件的契约,<form:form> 标签就无需通过 action 属性指定表单提交的 URL
 可以通过 modelAttribute 属性指定绑定的模型属性,若没有指定该属性,则默认从 request 域对象中读取 command 的表单 bean,如果该属性值也不存在,则会发生错误。
3) SpringMVC 提供了多个表单组件标签,如 <form:input/>、<form:select/> 等,用以绑定表单字段的属性值,它们的共有属性如下:
path:表单字段,对应 html 元素的 name 属性,支持级联属性
htmlEscape:是否对表单值的 HTML 特殊字符进行转换,默认值为 true
cssClass:表单组件对应的 CSS 样式类名
cssErrorClass:表单组件的数据存在错误时,采取的 CSS 样式
4) form:input、form:password、form:hidden、form:textarea:对应 HTML 表单的 text、password、hidden、textarea 标签
5) form:radiobutton:单选框组件标签,当表单 bean 对应的属性值和 value 值相等时,单选框被选中
6) form:radiobuttons:单选框组标签,用于构造多个单选框
items:可以是一个 List、String[] 或 Map
itemValue:指定 radio 的 value 值。可以是集合中 bean 的一个属性值
itemLabel:指定 radio 的 label 值
delimiter:多个单选框可以通过 delimiter 指定分隔符
7) form:checkbox:复选框组件。用于构造单个复选框
8) form:checkboxs:用于构造多个复选框。使用方式同 form:radiobuttons 标签
9) form:select:用于构造下拉框组件。使用方式同 form:radiobuttons 标签
10) form:option:下拉框选项组件标签。使用方式同 form:radiobuttons 标签
11) form:errors:显示表单组件或数据校验所对应的错误
<form:errors path= “*” /> :显示表单所有的错误
<form:errors path= “user*” /> :显示所有以 user 为前缀的属性对应的错误
<form:errors path= “username” /> :显示特定表单对象属性的错误

添加员工实验代码
1) 表单

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.*"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
 
<!-- 
1.为什么使用SpringMVC的form标签
① 快速开发
② 表单回显
2.可以通过modelAttribute指定绑定的模型属性,
若没有指定该属性,则默认从request域中查找command的表单的bean
如果该属性也不存在,那么,则会发生错误。
 -->
 <form:form action="empAdd" method="POST" modelAttribute="employee">
         LastName : <form:input path="lastName" /><br><br>
         Email : <form:input path="email" /><br><br>
         <%
                 Map<String,String> map = new HashMap<String,String>();
                 map.put("1", "Male");
                 map.put("0","Female");
                 request.setAttribute("genders", map);
         %>
         Gender : <br><form:radiobuttons path="gender" items="${genders }" delimiter="<br>"/><br><br>
         DeptName : 
                 <form:select path="department.id" 
                                                 items="${deptList }" 
                                                 itemLabel="departmentName" 
                                                 itemValue="id"></form:select><br><br>
                 <input type="submit" value="Submit"><br><br>
 </form:form> 
</body>
</html>

2) 控制器方法

@Controller
public class EmployeeHandler {
@RequestMapping(value="/empAdd",method=RequestMethod.POST)
public String empAdd(Employee employee){
employeeDao.save(employee);
return "redirect:/empList";
}
}

10 拦截器

10.1 自定义拦截器概述

1) Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现HandlerInterceptor接口,或者可以继承HandlerInterceptorAdapter 适配器类
preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false。
postHandle():这个方法在业务处理器处理完请求后,但是DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求request进行处理。
afterCompletion():这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。

实验代码(单个拦截器)
1) 自定义拦截器类

package com.atguigu.springmvc.interceptors;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
 
public class FirstHandlerInterceptor implements HandlerInterceptor {
 
@Override
public void afterCompletion(HttpServletRequest arg0,  HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
System.out.println(this.getClass().getName() + " - afterCompletion");
}
 
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,Object arg2, ModelAndView arg3) throws Exception {
System.out.println(this.getClass().getName() + " - postHandle");
}
 
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println(this.getClass().getName() + " - preHandle");
return true;
} 
}

2) 配置拦截器

<mvc:interceptors>
<!-- 声明自定义拦截器 -->
<bean id="firstHandlerInterceptor"
      class="com.atguigu.springmvc.interceptors.FirstHandlerInterceptor"></bean>
</mvc:interceptors>

在这里插入图片描述

11 Spring工作流程描述

在这里插入图片描述
Spring工作流程描述
1) 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获;
2) DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI):
判断请求URI对应的映射

  • ① 不存在:
     再判断是否配置了mvc:default-servlet-handler:
     如果没配置,则控制台报映射查找不到,客户端展示404错误
     如果有配置,则执行目标资源(一般为静态资源,如:JS,CSS,HTML)

  • ② 存在:
     执行下面流程
    3) 根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
    4) DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。
    5) 如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法【正向】
    6) 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
    ① HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
    ② 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
    ③ 数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
    ④ 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
    7) Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
    8) 此时将开始执行拦截器的postHandle(…)方法【逆向】
    9) 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet,根据Model和View,来渲染视图
    10) 在返回给客户端时需要执行拦截器的AfterCompletion方法【逆向】
    11) 将渲染结果返回给客户端

12 Spring整合SpringMVC

12.1 Spring 与SpringMVC的整合问题:

1) 需要进行 Spring 整合 SpringMVC 吗 ?
2) 还是否需要再加入 Spring 的 IOC 容器 ?
3) 是否需要在web.xml 文件中配置启动 Spring IOC 容器的 ContextLoaderListener ?

需要: 通常情况下, 类似于数据源, 事务, 整合其他框架都是放在 Spring 的配置文件中(而不是放在 SpringMVC 的配置文件中). 实际上放入 Spring 配置文件对应的 IOC 容器中的还有 Service 和 Dao.
不需要: 都放在 SpringMVC 的配置文件中. 也可以分多个 Spring 的配置文件, 然后使用 import 节点导入其他的配置文件
4) 如何启动Spring IOC容器?
非WEB环境: 直接在main方法或者是junit测试方法中通过new操作来创建.
WEB 环境: 我们希望SpringIOC容器在WEB应用服务器启动时就被创建.
通过监听器来监听 ServletContext对象的创建, 监听到ServletContext对象被创建,就创建SpringIOC容器
并且将容器对象绑定到ServletContext中, 让所有的web组件能共享到IOC容器对象.

12.2 Spring整合SpringMVC_解决方案配置监听器

1) 监听器配置

<!-- 配置启动 Spring IOC 容器的 Listener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

2) 创建Spring的bean的配置文件:beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 
<!-- 设置扫描组件的包 -->
<context:component-scan base-package="com.atguigu.springmvc"/>
 
<!-- 配置数据源, 整合其他框架, 事务等. -->
 
</beans>

3) springmvc配置文件:springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 
<!-- 设置扫描组件的包 -->
<context:component-scan base-package="com.atguigu.springmvc"/> 
<!-- 配置视图解析器 -->
<bean id="internalResourceViewResolver"
   class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
 
<mvc:default-servlet-handler/> 
<mvc:annotation-driven/> 
</beans>

在HelloWorldHandler、UserService类中增加构造方法,启动服务器,查看构造器执行情况。
问题: 若 Spring 的 IOC 容器和 SpringMVC 的 IOC 容器扫描的包有重合的部分, 就会导致有的 bean 会被创建 2 次.
解决:
使 Spring 的 IOC 容器扫描的包和 SpringMVC 的 IOC 容器扫描的包没有重合的部分.
使用 exclude-filter 和 include-filter 子节点来规定只能扫描的注解
springmvc.xml

<context:component-scan base-package="com.atguigu.springmvc" use-default-filters="false">
<context:include-filter type="annotation"
           expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation"
           expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>

beans.xml

<context:component-scan base-package="com.atguigu.springmvc">
<context:exclude-filter type="annotation"
        expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation"
        expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!-- 配置数据源, 整合其他框架, 事务等. -->

12.3 SpringIOC 容器和 SpringMVC IOC 容器的关系

SpringMVC 的 IOC 容器中的 bean 可以来引用 Spring IOC 容器中的 bean.
反之则不行. Spring IOC 容器中的 bean 却不能来引用 SpringMVC IOC 容器中的 bean
1) 在 Spring MVC 配置文件中引用业务层的 Bean
2) 多个 Spring IOC 容器之间可以设置为父子关系,以实现良好的解耦。
3) Spring MVC WEB 层容器可作为 “业务层” Spring 容器的子容器:
即 WEB 层容器可以引用业务层容器的 Bean,而业务层容器却访问不到 WEB 层容器的 Bean
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值