问:实际上SpringMVC就运行在Spring环境之下,还有必要整合么?SpringMVC和Spring都有IOC容器,是不是都需要保留呢?
答案是:通常情况下,类似于数据源,事务,整合其他框架都是放在spring的配置文件中(而不是放在SpringMVC的配置文件中),实际上放入Spring配置文件对应的IOC容器中的还有Service和Dao.而SpringMVC也搞自己的一个IOC容器,在SpringMVC的容器中只配置自己的Handler(Controller)信息。所以,两者的整合是十分有必要的,SpringMVC负责接受页面发送来的请求,Spring框架则负责整理中间需求逻辑,对数据库发送操作请求,对数据库的操作目前则先使用Spring框架中的JdbcTemplate进行处理。
1.导入Spring和SpringMVC的所有jar包
c3p0-0.9.1.2.jar
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.3.jar
mysql-connector-java-5.1.37-bin.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-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
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar
2.在web.xml文件中分别配置SpringMVC和Spring的配置信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
<!--
ContextLoaderListener 加载IOC容器,Spring框架的底层是listener --> <context-param> <param-name>contextConfigLocation</param-name> <!--
指定Spring的配置文件的路径和名称 --> <param-value>classpath:Spring.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> <!--
SpringMVC 配置文件 SpringMVC底层是servlet --> <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> <!--
设置编码,处理post请求乱码 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter- class >org.springframework.web.filter.CharacterEncodingFilter</filter- class > <init-param> <param-name>encoding</param-name> <param-value>UTF- 8 </param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--
post请求转化为put和delete --> <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter- class >org.springframework.web.filter.HiddenHttpMethodFilter</filter- class > </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
3.配置spring的配置文件和springmvc的配置文件
spring的配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
<!--
配置扫描的包 --> <context:component-scan
base- package = "com.neuedu" ></context:component-scan> <!--
加载properties文件中 信息 --> <context:property-placeholder
location= "classpath:jdbc.properties" /> <!--
配置数据源 --> <bean
id= "comboPooledDataSource" class = "com.mchange.v2.c3p0.ComboPooledDataSource" > <property
name= "user" value= "${jdbc.user}" ></property> <property
name= "password" value= "${jdbc.passowrd}" ></property> <property
name= "jdbcUrl" value= "${jdbc.url}" ></property> <property
name= "driverClass" value= "${jdbc.driver}" ></property> </bean> <!--
配置JdbcTemplate对应的bean, 并装配dataSource数据源属性--> <bean
id= "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate" > <property
name= "dataSource" ref= "comboPooledDataSource" ></property> </bean> <!--
为了执行带有具名参数的SQL语句,需要配置NamedParameterJdbcTemplate --> <!--
该NamedParameterJdbcTemplate类没有无参构造器,需要传入JdbcTemplate对象或者数据源对象[DataSource] --> <bean
id= "namedParameterJdbcTemplate" class = "org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate" > <!--
不能使用property标签配置哦 --> <constructor-arg
ref= "jdbcTemplate" ></constructor-arg> </bean> |
springmvc的配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<!--
配置扫描的包 --> <context:component-scan
base- package = "com.neuedu" ></context:component-scan> <!--
配置视图解析器 --> <bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver" > <property
name= "prefix" value= "/WEB-INF/views/" ></property> <property
name= "suffix" value= ".jsp" ></property> </bean> <!--
可以处理静态资源 --> <mvc: default -servlet-handler/> <!--
可以从一个页面直接通过请求到达另一个页面,不用通过controller --> <!--
<mvc:view-controller path= "/" view-name= "/" />
--> <!--
若只有mvc: default 没有mvc:annotation-driven,正常的requestMapping不能被访问,所以它俩是标配
--> <mvc:annotation-driven></mvc:annotation-driven> |
加入jdbc.properties文件:
1
2
3
4
|
jdbc.user=root <br>jdbc.passowrd= 123456 <br>jdbc.url=jdbc:mysql: //localhost:3306/jdbc_template <br>jdbc.driver=com.mysql.jdbc.Driver |
4.创建Controller类与Service类,并创建这两个类的无参构造器,分别输出一句话!
5.启动项目,会发现controller构造器和service构造器都执行了两次!
问题:若Spring的IOC容器和SpringMVC的IOC容器扫描的包有重合的部分,就会导致有的bean会被创建2次!
解决:
1.使Spring的IOC容器扫描的包和SpringMVC的IOC容器扫描的包没有重合的部分!
controller层都在controller包,service层都在service包
2.但是有的时候开发的时候是分模块开发的,这样不太容易做到,所以:
可以在component-scan标签下面中使用如下子标签来规定只能扫描的注解:
1
2
3
4
|
<context:component-scan
base- package = "com.neuedu" > <context:exclude-filter
type= "annotation" expression= "" /> <context:include-filter
type= "annotation" expression= "" /> </context:component-scan> |
所以在springMVC的配置文件中我们可以按着如下配置,只扫描controller及ControllerAdvice注解:
1
2
3
4
5
6
|
<context:component-scan
base- package = "com.neuedu" use- default -filters= "false" > <!--
扫描注解为 @Controller 的类
--> <context:include-filter
type= "annotation" expression= "org.springframework.stereotype.Controller" /> <!--
ControllerAdvice注解用来处理全局异常,可以标记在类上,故此处为扫描注解为 @ControllerAdvice 的类
--> <context:include-filter
type= "annotation" expression= "org.springframework.web.bind.annotation.ControllerAdvice" /> </context:component-scan> |
而在spring的配置文件中:
1
2
3
4
5
6
|
<context:component-scan
base- package = "com.neuedu" > <!--
扫描除了注解为 @Controller 的类
--> <context:exclude-filter
type= "annotation" expression= "org.springframework.stereotype.Controller" /> <!--
扫描除了注解为 @ControllerAdvice 的类
--> <context:exclude-filter
type= "annotation" expression= "org.springframework.web.bind.annotation.ControllerAdvice" /> </context:component-scan> |
此时再重新启动项目就会发现spring和springmvc的对象都创建了一份!
6.Spring的IOC容器和SpringMVC的IOC容器的关系
外边beans.xml为Spring的配置文件,黄色方格Spring-mvc.xml为SpringMVC的配置文件
注意:
1.SpringMVC容器中的bean可以引用Spring容器中的bean,也就是在Controller中我们可以注入service层对象【可以在controller层的requestMapping方法中打印service对象试一下】!
2.反之则不行,就是说:在spring扫描的service层不能引用springmvc的handler(Controller)对象【注解一个小例子,启动项目就会出错】
3.实际上Spring的容器和Spring容器有父子间关系,【参考图片】就像儿子可以继承父亲的基因一样,父亲没法继承儿子的基因!
而且从另一个角度也说明了Handler(Controller)是可以依赖Service层的,但是Service层却不可以依赖Handler(Controller)层!