一. Spring
1. Spring概述
-
Spring是一个开源框架
-
Spring为简化企业级开发而生,使用Spring,JavaBean就可以实现很多以前要靠EJB才能实现的功能。同样的功能,在EJB中要通过繁琐的配置和复杂的代码才能够实现,而在Spring中却非常的优雅和简洁。
-
Spring是一个IOC(DI)和AOP容器框架。
-
Spring的优良特性
依赖注入:DI——Dependency Injection,反转控制(IOC)最经典的实现。
面向切面编程:Aspect Oriented Programming——AOP
一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。 -
Spring模块
2. IOC 和 DI 简介
2.1 IOC(Inversion of Control):反转控制
在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式,增加了学习成本,同时降低了开发效率。
反转控制的思想完全颠覆了应用程序组件获取资源的传统方式:反转了资源的获取方向——改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效率。这种行为也称为查找的被动形式。
通俗点说就是组件获取容器中的对象的方式由主动变为被动
2.2 DI(Dependency Injection):依赖注入
IOC的另一种表述方式:即组件以一些预先定义好的方式(例如:setter 方法)接受来自于容器的资源注入。相对于IOC而言,这种表述更直接。
IOC 描述的是一种思想,而DI 是对IOC思想的具体实现。
3. Spring Bean配置
3.1 Bean配置解释
<bean>: 让IOC容器管理一个具体的对象.
id: 唯一标识
class: 类的全类名. 通过反射的方式创建对象.
Class cls = Class.forName("helloworld.Hello");
Object obj = cls.newInstance(); 无参数构造器
<property>: 给对象的属性赋值.
name: 指定属性名 ,要去对应类中的set方法.
value:指定属性值
3.2 获取bean的方式
applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置bean
id属性,给当前bean起一个名字,该名称必须唯一
class属性,设置bean的全类名,Spring会利用反射技术实例化该bean
-->
<bean id="hello" class="helloworld.Hello">
<!-- 给属性赋值
name属性:设置bean的属性名 setName中set后的小写字母name
value属性:设置bean的属性值
-->
<property name="name" value="Spring1"></property>
</bean>
</beans>
/**
* 获取bean的方式
* 1. 根据名称(id属性值)获取
* Hello hello = (Hello)ioc.getBean("hello");
*
* 2.根据bean的类型获取
* -要求:IOC容器中该类型的bean是唯一的,否则会抛出异常
* 即 class="helloworld.Hello" 只能有一个
*/
// 1. id属性值获取
Hello hello1 = (Hello)ioc.getBean("hello");
// 2. bean类型获取 这个不用强转
Hello hello2 = ioc.getBean(Hello.class);
3.3 给bean的属性赋值
给bean的属性赋值方式
- 通过value属性赋值: integer string等基本类型可以用value
- 通过ref属性赋值: 引用类型属性用ref
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
给bean的属性赋值方式
1.通过value属性赋值 integer string等基本类型可以用value
2.通过ref属性赋值 引用类型属性用ref
-->
<bean id="employee" class="bean.Employee">
<property name="id" value="1"></property>
<property name="name" value="a"></property>
<property name="email" value="a@qq.com"></property>
<property name="dept" ref="department"></property>
<!-- 通过级联属性修改属性值 因为默认单例设计模式,所以最终department的id值为10086-->
<property name="dept.id" value="10086"></property>
</bean>
<bean id="department" class="bean.Department">
<property name="id" value="10010"></property>
<property name="name" value="天才部"></property>
</bean>
</beans>
3.4 引用外部属性文件
当bean的配置信息逐渐增多时,查找和修改一些bean的配置信息就变得愈加困难。这时可以将一部分信息提取到bean配置文件的外部,以properties格式的属性文件保存起来,同时在bean的配置文件中引用properties属性文件中的内容,从而实现一部分属性值在发生变化时仅修改properties属性文件即可。这种技术多用于连接数据库的基本信息的配置。
<!-- 直接配置数据源 -->
<!-- <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
<property name="url" value="jdbc:mysql://localhost:3306/yiibaidb?serverTimezone=UTC"></property>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
</bean> -->
<!-- 引入外部包含连接数据库有关信息的属性文件 -->
<context:property-placeholder location="classpath:druid.properties"/>
<!-- 引用外部文件配置数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- 配置连接数据库相关信息属性 -->
<!-- 一定要在username前加东西 例如jdbc.username,不然会读成本机系统的username -->
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="initialSize" value="${jdbc.initialSize}"></property>
<property name="minIdle" value="${jdbc.minIdle}"></property>
<property name="maxActive" value="${jdbc.maxActive}"></property>
<property name="maxWait" value="${jdbc.maxWait}"></property>
</bean>
4. 基于注解配置bean
4.1 自动装配
- 手动装配:以value或ref的方式明确指定属性值都是手动装配。
- 自动装配:根据指定的装配规则,不需要明确指定,Spring自动将匹配的属性值注入bean中。
4.2 通过注解配置bean
- 普通组件:@Component
标识一个受Spring IOC容器管理的组件 - 持久化层(Dao)组件:@Repository
标识一个受Spring IOC容器管理的持久化层组件 - 业务逻辑层(Service)组件:@Service
标识一个受Spring IOC容器管理的业务逻辑层组件 - 表述层控制器组件:@Controller
标识一个受Spring IOC容器管理的表述层控制器组件 - 组件命名规则
①默认情况:使用组件的简单类名首字母小写后得到的字符串作为bean的id
②使用组件注解的value属性指定bean的id
注意:事实上Spring并没有能力识别一个组件到底是不是它所标记的类型,即使将@Respository注解用在一个表述层控制器组件上面也不会产生任何错误,所以 @Respository、@Service、@Controller这几个注解仅仅是为了让开发人员自己明确当前的组件扮演的角色。
Dao层实现类
/*
* 通过注释将当前类交给IOC容器管理之后,
* 默认在IOC容器中对象的id是类名的首字母小写 userDaoImpl
* 可以通过value属性来指定该id,而且value可以不写
*/
//@Repository(value="userDao")
@Repository("userDao")
public class UserDaoImpl implements UserDao{
@Override
public void saveUser() {
System.out.println("User信息被保存了");
}
}
Service层实现类
@Service("userService")
public class UserServiceImpl implements UserService{
@Autowired
private UserDao userDao;
@Override
public void saveUser() {
System.out.println("service的saveUser()方法,调用dao层saveUser()");
userDao.saveUser();
}
}
4.3 扫描组件
在Dao或Service等层的实现类加了注解,但是spring怎么知道呢?通过配置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">
<!-- 设置手动扫描的包
base-package属性:设置一个基础包,spring会自动扫描该包以及该子包
-->
<context:component-scan base-package="annotation" use-default-filters="false">
<!--include-filter:用来设置只扫描哪个包下的类,此时需要将父标签的use-default-filters属性的值设置为false
如果type的值是annotation,那么expression的值是注解的全类名
例如扫描annotation.dao包:org.springframework.stereotype.Repository
如果type的值是assignable,那么expression的值是接口或实现类的全类名
例如扫描annotation.dao包:annotation.dao.UserDao
-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
<context:component-scan base-package="annotation" >
<!-- exclude-filter:用来设置不扫描哪个包下的类
如果type的值是annotation,那么expression的值是注解的全类名 例如扫描annotation.dao包 org.springframework.stereotype.Repository
如果type的值是assignable,那么expression的值是接口或实现类的全类名 annotation.dao.UserDao
-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
</beans>
4.4 组件装配
Service层实现类
@Service("userService")
public class UserServiceImpl implements UserService{
/*
* 在Service层需要调用Dao层方法是,传统是new UserDaoImpl()一个对象
* 但在spring中可以通过添加@Autowired注解实现自动装配
* @Autowired
private UserDao userDao;
*/
/*
* 自动装配规则:
* 1. 根据属性类型实现自动装配
*
* 2. 如果根据类型无法实现自动装配(例如有两个UserDao实现类),会以属性名作为id从IOC容器中寻找以实现自动装配
* 例如在UserDaoImpl中 @Repository("userDao") 在UserDaoImpl2中 @Repository("userDao2")
* 会装配UserDaoImpl
*
* 3. 但假如UserDaoImpl中 @Repository("userDao1"),通过1和2都不能实现自动装配
* 可以通过@Qualifier的value属性来指定id实现自动装配,并且value可省略不写
*/
@Qualifier("userDao2")
@Autowired
private UserDao userDao;
/*
* 添加了@Autowired注解的属性默认必须注入成功,否则抛异常
* 但可以通过required属性的值为false来告诉Spring当前属性可以不装配
* 不装配就是null,空指针,但不会报错
*/
@Autowired(required=false)
private User user;
@Override
public void saveUser() {
System.out.println("service 的saveUser()方法,调用dao层");
userDao.saveUser();
}
}
二. SpringMVC
1. SpringMVC 概述
- 一种轻量级的、基于MVC的Web层应用框架。偏前端而不是基于业务逻辑层。Spring框架的一个后续产品;
- Spring 为展现层提供的基于 MVC 设计理念的优秀的 Web 框架,是目前最主流的 MVC 框架之一;
- Spring MVC 通过一套 MVC 注解,让 POJO 成为处理请求的控制器,而无须实现任何接口。
执行流程:
- 启动服务器,加载一些配置文件
(1) 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_2_5.xsd" id="WebApp_ID" version="2.5">
<!-- 配置前端控制器:DispatchServlet,快捷键:Alt + / 选中倒数第二项 -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 配置SpringMVC配置文件的路径 -->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<!-- 配置映射的请求地址,设置为:/ -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
DispatcherServlet对象被创建 以及 springmvc.xml配置文件被加载
(2) 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="helloworld"></context:component-scan>
<!-- 配置视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置前缀 -->
<property name="prefix" value="/WEB-INF/views/"></property>
<!-- 配置后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 使springmvc的注解生效,例如 @RequestMapping -->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
此时自动扫描的包下注解了@Controller的类HelloWorld被创建成对象,以及通过配置方式生成的bean对象:视图解析器
- 发送请求,后台处理流程:
2. @RequestMapping 映射请求注解
2.1 @RequestMapping 概念
- SpringMVC使用@RequestMapping注解为控制器指定可以处理哪些 URL 请求
- 作用:DispatcherServlet 截获请求后,就通过控制器上 @RequestMapping 提供的映射信息确定请求所对应的处理方法。
2.2 标注位置
类和方法上
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("/springmvc")
@Controller
//这个类是一个处理器
public class HelloWorld {
/*
* 方法的返回值会被springmvc配置文件的InternalResourceViewResolver这个视图解析器解析为真实的物理视图
* 然后自动进行请求的转发
* 真实的物理视图 = 前缀 + 方法的返回值 + 后缀
* 即 /WEB-INF/views/success.jsp
*/
@RequestMapping("/hello")
public String testHelloWorld(){
System.out.println("hello springmvc!");
return "success";
}
}
同时标注在类和方法上,则此时要映射的请求路径为 /springmvc/hello;
如果只在方法上标注,此时的路径为 /hello
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!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=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<a href="${pageContext.request.contextPath }/springmvc/hello">Hello Springmvc </a>
</body>
</html>
2.3 @RequestMapping 映射请求URL与 请求方式
@RequestMapping注解中的属性:
- value:用来设置要映射的请求地址,值的类型是String类型的数组
如果只映射一个请求地址,那么value的值不需要添加大括号{},value属性名可以省略不写 - method:用来设置映射的请求方式
如果没有设置该属性,那么只看映射的请求地址,不管请求方式
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@RequestMapping("/springmvc")
@Controller
//这个类是一个处理器
public class HelloWorld {
@RequestMapping("/hello")
public String testHelloWorld(){
System.out.println("hello springmvc!");
return "success";
}
//映射多个请求地址
@RequestMapping(value={"/testValue","/testValue2"})
public String testValue(){
System.out.println("hello testValue!");
return "success";
}
//请求方式为post
@RequestMapping(value="/testMethod",method=RequestMethod.POST)
public String testMethod(){
System.out.println("hello testMethod!");
return "success";
}
}
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!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=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<a href="${pageContext.request.contextPath }/springmvc/hello">Hello Springmvc </a>
<a href="${pageContext.request.contextPath }/springmvc/testValue">Test Value </a>
<a href="${pageContext.request.contextPath }/springmvc/testValue2">Test Value2 </a>
<a href="${pageContext.request.contextPath }/springmvc/testMethod">Test Method </a>
<form action="${pageContext.request.contextPath }/springmvc/testMethod" method="post">
<input TYPE="submit" value="Test Method">
</form>
</body>
</html>
3. 处理请求数据
3.1 @RequestParam注解
在处理方法入参处使用 @RequestParam 可以把请求参数传递给请求方法
用来映射请求参数,该注解的属性:
- value:设置请求参数的参数名
- required:设置请求参数是否是必须的,默认是true
- defaultValue:设置请求参数的默认值,如果没有传入该请求参数将使用该值
<a href="${pageContext.request.contextPath }/springmvc/testParam?username=admin">Test RequestParam </a>
@RequestMapping(value="/testParam")
public String testRequestParam(@RequestParam(value="username")String name,
@RequestParam(value="age",required=false,defaultValue="0")int age){
System.out.println("hello testParam!");
System.out.println("用户名:" + name + "年龄:" + age);
return "success";
}
解释:
1)假如方法入参处如下:
public String testRequestParam(@RequestParam(value="username")String name,@RequestParam(value="age")Integer age)
则会出错,因为在jsp文件中/springmvc/testParam?username=admin
,没有输入age以及数值;此时可以加上required=false
,即
public String testRequestParam(@RequestParam(value="username")String name,@RequestParam(value="age",required=false)Integer age)
2)假如方法入参处如下:
public String testRequestParam(@RequestParam(value="username")String name,@RequestParam(value="age",required=false)int age)
将Integer改成int,会报错,因为无法将null类型转换成Integer包装类型,此时可以加上默认值defaultValue="0"
3.2 使用POJO作为参数
1)使用 POJO 对象绑定请求参数值
2)Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值。支持级联属性。如:dept.deptId、dept.address.tel 等
要求:<input type="text" name="id">
中name的值一定要和Employee和Department中的属性名字一样
<!-- 写中文会出现乱码问题,可改成UTF-8-->
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<form action="${pageContext.request.contextPath }/springmvc/testPOJO" method="post">
员工id:<input type="text" name="id"><br>
员工name:<input type="text" name="ename"><br>
员工email:<input type="text" name="email"><br>
部门id:<input type="text" name="dept.id"><br>
部门name:<input type="text" name="dept.name"><br>
<input TYPE="submit" value="Test POJO">
</form>
@RequestMapping(value="/testPOJO")
public String testPOJO(Employee employee){
System.out.println("员工信息是:"+employee);
return "success";
}
3.3 使用Servlet原生API作为参数
MVC 的 Handler 方法可以接受哪些 ServletAPI 类型的参数
- HttpServletRequest
- HttpServletResponse
- HttpSession
- java.security.Principal
- Locale
- InputStream
- OutputStream
- Reader
- Write
<a href="${pageContext.request.contextPath }/springmvc/testServletAPI?username=admin">Test ServletAPI </a><br>
//使用Servlet原生API作为参数
@RequestMapping(value="/testServletAPI")
public String testServletAPI(HttpServletRequest request,HttpServletResponse response){
String username = request.getParameter("username");
System.out.println(username);
String age = request.getParameter("age");
System.out.println(age);
return "success";
}
4. 处理响应数据
1)ModelAndView: 处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据
2)Map 及 Model: 入参为 org.springframework.ui.Model、org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中。
4.1 处理响应数据之 ModelAndView
1)控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数据信息。
2)添加模型数据:
MoelAndView addObject(String attributeName, Object attributeValue)
ModelAndView addAllObject(Map<String, ?> modelMap)
3)设置视图:
void setView(View view)
void setViewName(String viewName)
设置超链接
<a href="${pageContext.request.contextPath }/springmvc/testModelAndView">Test ModelAndView </a><br>
编写处理方法
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
//1.创建ModelAndView对象
ModelAndView mv = new ModelAndView();
//假设从数据库中查询出来一个Employee对象 里面就是模型数据
Employee employee = new Employee(1,"张三丰","a@b.com",null);
//2.将模型数据设置到ModelAndView对象中
mv.addObject("emp", employee);
//3.设置视图名
mv.setViewName("success");
return mv;
}
在视图上显示数据
<h1>${emp }</h1>
结果:
4.2 处理响应数据之 Map 、Model
1)Spring MVC 在内部使用了一个 org.springframework.ui.Model 接口存储模型数据
具体使用步骤
2)Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
3)如果方法的入参为 Map 或 Model 类型,Spring MVC 会将隐含模型的引用传递给这些入参。
4)在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据
相比ModelAndView,这种方法更加便捷。
/*
* 处理响应数据方式2:在Handler犯法入参处传入Map、Model、ModelMap
* 不管是将Handler方法返回值设置为ModelAndView还是在Handler方法入参处传入Map、Model、ModelMap
* SpringMVC都会转换为一个ModelAndView对象
*/
@RequestMapping("/testMap")
public String testMap(Map<String,Object> map){
//假设从数据库中查询出来一个Employee对象
Employee employee = new Employee(1,"张三丰","a@b.com",null);
//将employee对象放到map中,最后会放到request域中
map.put("emp",employee);
return "success";
}
结果:
4.3 @ResponseBody注解
在Handler方法上添加该注解之后,方法的返回值将以字符串的形式直接响应给浏览器。可以加到类上或方法上。
在类上添加了@ResponseBody注解之后,Handler的方法的返回值将直接返回给浏览器,但是前提是在springmvc的配置文件中配置了<mvc:annotation-driven />
标签。
设置超链接
<a href="${pageContext.request.contextPath }/springmvc/testResponseBody">Test ResponseBody </a><br>
处理方法
@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
System.out.println("testResponseBody");
return "success";
}
结果:
4.4 重定向
1)一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理
2)如果返回的字符串中带 forward: 或 redirect: 前缀时,SpringMVC 会对他们进行特殊处理:将 forward: 和 redirect: 当成指示符,其后的字符串作为 URL 来处理
3)redirect:success.jsp:会完成一个到 success.jsp 的重定向的操作
4)forward:success.jsp:会完成一个到 success.jsp 的转发操作
<a href="${pageContext.request.contextPath }/springmvc/testReDirect">Test ReDirect </a><br>
/*
* 重定向
*/
@RequestMapping("/testReDirect")
public String testReDirectDirect(){
System.out.println("testReDirect");
//可以重定向到jsp页面
//return "forward:/redirect.jsp";
//也可以到其他方法
return "redirect:/springmvc/testMap";
}
三. Spring与SpringMVC的整合
Spring和SpringMVC的整合:
- Spring的IOC容器负责配置Dao、Service、数据源、事务以及其他框架的整合
- SpringMVC负责配置Handler、视图解析器
问题1:在SpringMVC中DispatcherServlet会帮我们自动初始化SpringMVC的IOC容器,那Spring的IOC容器如何初始化?
- Java工程: new ClassPathXmlApplicationContext(“beans.xml”),但在web中,请求已经发过来了,难道先让请求等一下,我先初始化一下我的IOC容器?
- Web工程:在web.xml中配置ContextLoaderListener监听器,此时会同步初始化Spring的IOC容器
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_2_5.xsd" id="WebApp_ID" version="2.5">
<!-- 配置DispatcherServlet -->
<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 配置ContextLoaderListener 监听器,用来初始化Spring的配置文件,Alt+/ 倒数第三项 -->
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
问题2:在beans.xml与springmvc.xml中,都各自创建了Handler和Service对象,即Handler和Service对象被创建了两次。
- Spring不扫描Handler
- SpingMVC只扫描Handler
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="SS">
<!-- 设置不扫描Handler -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
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"
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="SS" use-default-filters="false">
<!-- 设置只扫描Handler -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<bean id="ViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置前缀 -->
<property name="prefix" value="/WEB-INF/views/"></property>
<!-- 配置后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>