SpringMVC配置文件

现在主流的Web MVC框架除了Struts这个主力 外,其次就是Spring MVC了,因此这也是作为一名程序员需要掌握的主流框架,框架选择多了,应对多变的需求和业务时,可实行的方案自然就多了。不过要想灵活运用Spring MVC来应对大多数的Web开发,就必须要掌握它的配置及原理。

 

服务器启动时配置文件的执行顺序为:

1.web.xml

2.application-context.xml spring的配置文件。

3.servlet-context.xml SpringMVC的配置文件。

一.web.xml配置

1.web工程中的web.xml文件有什么作用呢?它是每个web.xml工程都必须的吗?

一个web中完全可以没有web.xml文件,也就是说,web.xml文件并不是web工程必须的。

那什么时候需要,什么时候可以不需要呢?

要想回答上面的问题,得先了解web.xml文件使用来干什么的。web.xml文件是用来配置:欢迎页、servlet、filter等的。当你的web工程没用到这些时,你可以不用web.xml文件来配置你的web工程。

 

那么web.xml能做的所有事情都有那些?

 

其实,web.xml的模式(Schema)文件中定义了多少种标签元素,web.xml中就可以出现它的模式文件所定义的标签元素,它就能拥有定义出来的那些功能。web.xml的模式文件是由Sun公司定义的,每个web.xml文件的根元素<web-app>中,都必须标明这个web.xml使用的是哪个模式文件。如:

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5"

 xmlns="http://Java.sun.com/xml/ns/javaee"

 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

 xsi:schemaLocation="http://Java.sun.com/xml/ns/javaee

 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

</web-app>

 

 

 

   而且web.xml的模式文件中定义的标签并不是定死的,模式文件也是可以改变的,一般来说,随着web.mxl模式文件的版本升级,里面定义的功能会越来越复杂,也即标签元素的种类会越来越多,但有些是不常用的,我们只需记住一些常用的就可以了。

 

 

   下面列出web.xml常用的标签元素及这些标签元素的功能:

 

1.1、指定欢迎页面,例如:

<welcome-file-list>

  <welcome-file-list>

    <welcome-file>index.jsp</welcome-file>

    <welcome-file>index1.jsp</welcome-file>

  </welcome-file-list>

 

上面的例子指定了2个欢迎页面,显示时按顺序从第一个找起,如果第一个存在,就显示第一个,后面的不起作用。如果第一个不存在,就找第二个,以此类推。

 

 

关于欢迎页面:

 

   访问一个网站时,默认看到的第一个页面就叫欢迎页,一般情况下是由首页来充当欢迎页的。一般情况下,我们会在web.xml中指定欢迎页。但web.xml并不是一个Web的必要文件,没有web.xml,网站仍然是可以正常工作的。只不过网站的功能复杂起来后,web.xml的确有非常大用处,所以,默认创建的动态web工程在WEB-INF文件夹下面都有一个web.xml文件。

      对于tomcat来说,当你只指定一个web的根名,没有指定具体页面,去访问时一个web时,如果web.xml文件中配置了欢迎页,那么就返回指定的那个页面作为欢迎页,而在文中没有web.xml文件,或虽然有web.xml,但web.xml也没指定欢迎页的情况下,它默认先查找index.html文件,如果找到了,就把index.html作为欢迎页还回给浏览器。如果没找到index.html,tomcat就去找index.jsp。找到index.jsp就把它作为欢迎页面返回。而如果index.html和index.jsp都没找到,又没有用web.xml文件指定欢迎页面,那此时tomcat就不知道该返回哪个文件了,它就显示The requested resource (/XXX) is not available的页面。其中XXX表示web的根名。但如果你指定了具体页面,是可以正常访问的。

 

1.2、命名与定制URL。我们可以为Servlet和JSP文件命名并定制URL,其中定制URL是依赖一命名的,命名必须在定制URL前。下面拿serlet来举例:

(1)、为Servlet命名:

<servlet>

    <servlet-name>servlet1</servlet-name>

    <servlet-class>net.test.TestServlet</servlet-class>

</servlet>

 

 

 

(2)、为Servlet定制URL、

<servlet-mapping>

    <servlet-name>servlet1</servlet-name>

    <url-pattern>*.do</url-pattern>

</servlet-mapping>

 

1.3、定制初始化参数:可以定制servlet、JSP、Context的初始化参数,然后可以再servlet、JSP、Context中获取这些参数值。下面哪servlet来举例:

<servlet>

    <servlet-name>servlet1</servlet-name>

    <servlet-class>net.test.TestServlet</servlet-class>

    <init-param>

          <param-name>userName</param-name>

          <param-value>Tommy</param-value>

    </init-param>

    <init-param>

          <param-name>E-mail</param-name>

          <param-value>Tommy@163.com</param-value>

    </init-param>

</servlet>

 

经过上面的配置,在servlet中能够调用getServletConfig().getInitParameter("param1")获得参数名对应的值。

 

 

1.4、指定错误处理页面,可以通过“异常类型”或“错误码”来指定错误处理页面。

<error-page>

    <error-code>404</error-code>

    <location>/error404.jsp</location>

</error-page>

-----------------------------

<error-page>

    <exception-type>java.lang.Exception<exception-type>

    <location>/exception.jsp<location>

</error-page>

 

1.5、设置过滤器:比如设置一个编码过滤器,过滤所有资源

<filter>

    <filter-name>XXXCharaSetFilter</filter-name>

    <filter-class>net.test.CharSetFilter</filter-class>

</filter>

<filter-mapping>

    <filter-name>XXXCharaSetFilter</filter-name>

    <url-pattern>/*</url-pattern>

</filter-mapping>

 

1.6、设置监听器:

<listener>

    <listener-class>net.test.XXXLisenet</listener-class>

</listener>

2.WEB工程加载web.xml过程

  经过个人测试,WEB工程加载顺序与元素节点在文件中的配置顺序无关。即不会因为 filter 写在 listener 的前面而会先加载 filter。WEB容器的加载顺序是:ServletContext -> context-param -> listener -> filter -> servlet。并且这些元素可以配置在文件中的任意位置。

  加载过程顺序如下:

  1. 启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取<listener>和<context-param>两个结点。 
  2. 紧急着,容创建一个ServletContext(servlet上下文),这个web项目的所有部分都将共享这个上下文。 
  3. 容器将<context-param>转换为键值对,并交给servletContext。 
  4. 容器创建<listener>中的类实例,创建监听器。 



二.Spring配置文件:application-context.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-2.5.xsd">  
    <!-- 定义使用C3P0连接池的数据源 -->  
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  
        <!-- 指定连接数据库的JDBC驱动 -->  
        <property name="driverClass">  
            <value>com.mysql.jdbc.Driver</value>  
        </property>  
        <!-- 连接数据库所用的URL -->  
        <property name="jdbcUrl">  
            <value>jdbc:mysql://localhost:3306/eportal?useUnicode=  
                true&characterEncoding=gbk</value>  
        </property>  
        <!-- 连接数据库的用户名 -->  
        <property name="user">  
            <value>root</value>  
        </property>  
        <!-- 连接数据库的密码 -->  
        <property name="password">  
            <value>root</value>  
        </property>  
        <!-- 设置数据库连接池的最大连接数 -->  
        <property name="maxPoolSize">  
            <value>20</value>  
        </property>  
        <!-- 设置数据库连接池的最小连接数 -->  
        <property name="minPoolSize">  
            <value>2</value>  
        </property>  
        <!-- 设置数据库连接池的初始化连接数 -->  
        <property name="initialPoolSize">  
            <value>2</value>  
        </property>  
        <!-- 设置数据库连接池的连接的最大空闲时间,单位为秒 -->  
        <property name="maxIdleTime">  
            <value>20</value>  
        </property>  
    </bean>  
    <!-- 定义Hibernate的SessionFactory -->  
    <bean id="sessionFactory"  
        class="org.springframework.orm.  
hibernate3.LocalSessionFactoryBean">  
        <!-- 依赖注入上面定义的数据源dataSource -->  
        <property name="dataSource" ref="dataSource" />  
        <!-- 注册Hibernate的ORM映射文件 -->  
        <property name="mappingResources">  
            <list>  
                <value>com/eportal/ORM/News.hbm.xml</value>  
                <value>com/eportal/ORM/Category.hbm.xml</value>    
            </list>  
        </property>  
        <!-- 设置Hibernate的相关属性 -->  
        <property name="hibernateProperties">  
            <props>  
                <!-- 设置Hibernate的数据库方言 -->  
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>  
                <!-- 设置Hibernate是否在控制台输出SQL语句,开发调试阶段通常设为true -->  
                <prop key="show_sql">true</prop>  
                <!-- 设置Hibernate一个提交批次中的最大SQL语句数 -->  
                <prop key="hibernate.jdbc.batch_size">50</prop>  
                <prop key="show_sql">50</prop>  
            </props>  
        </property>  
    </bean>  
    <!--定义Hibernate的事务管理器HibernateTransactionManager -->  
    <bean id="transactionManager"  
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
        <!-- 依赖注入上面定义的sessionFactory -->  
        <property name="sessionFactory" ref="sessionFactory" />  
    </bean>  
    <!--定义Spring的事务拦截器TransactionInterceptor -->  
    <bean id="transactionInterceptor"  
        class="org.springframework.transaction.interceptor.TransactionInterceptor">  
        <!-- 依赖注入上面定义的事务管理器transactionManager -->  
        <property name="transactionManager" ref="transactionManager" />  
        <!-- 定义需要进行事务拦截的方法及所采用的事务控制类型 -->  
        <property name="transactionAttributes">  
            <props>  
                <!-- 以browse、list、load、get及is开头的所有方法采用只读型事务控制类型 -->  
                <prop key="browse*">PROPAGATION_REQUIRED,readOnly</prop>  
                <prop key="list*">PROPAGATION_REQUIRED,readOnly</prop>  
                <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>  
                <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>  
                <prop key="is*">PROPAGATION_REQUIRED,readOnly</prop>  
                <!-- 所有方法均进行事务控制,如果当前没有事务,则新建一个事务 -->  
                <prop key="*">PROPAGATION_REQUIRED</prop>  
            </props>  
        </property>  
    </bean>  
    <!-- 定义BeanNameAutoProxyCreatorf进行Spring的事务处理 -->  
    <bean  
        class="org.springframework.aop.framework.autoproxy.    
BeanNameAutoProxyCreator">  
        <!-- 针对指定的bean自动生成业务代理 -->  
        <property name="beanNames">  
            <list>  
                <value>adminService</value>  
                <value>columnsService</value>  
                <value>newsService</value>  
                <value>crawlService</value>  
                <value>memberLevelService</value>  
                <value>memberService</value>  
                <value>categoryService</value>  
                <value>merService</value>  
                <value>cartService</value>  
                <value>ordersService</value>  
                <value>trafficService</value>  
            </list>  
        </property>  
        <!-- 这个属性为true时,表示被代理的是目标类本身而不是目标类的接口 -->  
        <property name="proxyTargetClass">  
            <value>true</value>  
        </property>  
        <!-- 依赖注入上面定义的事务拦截器transactionInterceptor -->  
        <property name="interceptorNames">  
            <list>  
                <value>transactionInterceptor</value>  
            </list>  
        </property>  
    </bean>  
    <!-- 装配通用数据库访问类BaseDAOImpl -->  
    <bean id="dao" class="com.eportal.DAO.BaseDAOImpl">  
        <property name="sessionFactory" ref="sessionFactory" />  
    </bean>  
    <!-- 部署系统用户管理业务逻辑组件AdminServiceImpl -->  
    <bean id="adminService" class="com.eportal.service.AdminServiceImpl">  
        <property name="dao" ref="dao" />  
    </bean>  
    <!-- 部署新闻栏目管理业务逻辑组件ColumnsServiceImpl -->  
    <bean id="columnsService" class="com.eportal.service.ColumnsServiceImpl">  
        <property name="dao" ref="dao" />  
    </bean>  
      
    <!-- 部署订单管理业务逻辑组件OrderServiceImpl -->  
    <bean id="ordersService" class="com.eportal.service.OrderServiceImpl">  
        <property name="dao" ref="dao" />  
    </bean>  
    <!-- 部署流量统计业务逻辑组件TrafficServiceImpl -->  
    <bean id="trafficService" class="com.eportal.service.TrafficServiceImpl">  
        <property name="dao" ref="dao" />  
    </bean>  
    <!-- 部署Struts 2负责系统用户管理的控制器AdminAction -->  
    <bean id="adminAction" class="com.eportal.struts.action.  
AdminAction"  
        scope="prototype">  
        <property name="service" ref="adminService" />  
    </bean>  
    <!-- 部署Struts 2负责新闻栏目管理的控制器ColumnsAction -->  
    <bean id="columnsAction" class="com.eportal.struts.action.  
ColumnsAction"  
        scope="prototype">  
        <property name="service" ref="columnsService" />  
    </bean>  
    <!-- 部署Struts 2负责新闻管理的控制器NewsAction -->  
    <bean id="newsAction" class="com.eportal.struts.action.  
NewsAction"  
        scope="prototype">  
        <property name="service" ref="newsService" />  
        <property name="columnsService" ref="columnsService" />  
    </bean>  
    <!-- 部署Struts 2负责新闻采集规则管理的控制器CrawlAction -->  
    <bean id="crawlAction" class="com.eportal.struts.action.  
CrawlAction"  
        scope="prototype">  
        <property name="service" ref="crawlService" />  
        <property name="columnsService" ref="columnsService" />  
    </bean>  
      
</beans>   


2.1 引用外部属性文件
 

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations">
   <list>
    <value>classpath:mail.properties</value>
    <value>classpath:jdbc.properties</value>
   </list>
  </property>
 </bean>


我们定义了一个PropertyPlaceholderConfigurer类的实例,并将其位置属性设置为我们的属性文件。该类被实现为Bean工厂的后处理器,并将使用定义在文件中的属性来代替所有的占位符(${...}value)。
注意:
而在spring2.5的版本中提供了一种更简便的方式,如:

<context:property-placeholder location="classpath:config/jdbc.properties"/> 

这样以后要使用属性文件中的资源时,可以使用${属性名}来获得。


2.2 常用数据源的配置
第一种是:DBCP数据源,(需要加入2个jar文件,在spring中的lib下jakarta-commons/commons-dbcp.jar和commons-pools.jar)主要配置如下:

使用:org.apache.commons.dbcp.BasicDataSource进行配置
 

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">


   <!-- 【必须】  数据库驱动-->
   <property name="driverClassName" value="${jdbc.driver}" />
   <!-- 【必须】 数据库连接地址 -->
   <property name="url" value="${jdbc.url}" />
   <!-- 【必须】 数据库用户名 -->
   <property name="username" value="${jdbc.username}" />
   <!-- 【必须】 数据库密码 -->
   <property name="password" value="${jdbc.password}" />
   <!-- 可选 启动时创建的连接数 -->
   <property name="initialSize" value="5"/>
   <!-- 可选 同时可从池中分配的最多连接数,0无限制 -->
   <property name="maxActive" value="10"/>
   <!-- 可选 池中不会被释放的最多空闲连接数 0无限制 -->
   <property name="maxIdle" value=""/>
   <!-- 可选 同时能从语句池中分配的预处理语句最大值,0无限制 -->
   <property name="maxOpenPreparedStatement" value="100"/>
   <!-- 可选 抛异常前池等待连接回收最大时间(当无可用连接),-1无限等待 -->
   <property name="maxWait" value="1000"/>
   <!-- 可选 连接在池中保持空闲而不被回收的最大时间 -->
   <property name="minEvictableIdleTimeMillis" value="2000"/>
   <!-- 可选 不创建新连接情况下池中保持空闲的最小连接数 -->
   <property name="minIdle" value="2"/>
   <!-- 可选 布尔值,是否对预处理语句进行池管理 -->
   <property name="poolPreparedStatements" value="true"/>
</bean>

第二种是:c3p0数据源,跟第一种一个类型,需加入c3p0.jar包。
使用:com.mchange.v2.c3p0.ComboPooledDataSource进行配置

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">


   <property name="driverClass" value="${jdbc.driver}" />


   <property name="jdbcUrl" value="${jdbc.url}" />


   <property name="user" value="${jdbc.username}" />
   <property name="password" value="${jdbc.password}" />

</bean>

第三种是:JNDI数据源,配置在高性能的应用服务器(如WebLogic、WebSphere等)

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 
      <property name="jndiName" value="java:comp/env/jdbc/bbt"/> 
</bean> 

从spring2.0开始提供jee命名空间,可以简化配置如下:

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/bbt"/> 

2.3配置事务管理器
2.3.1、Spring JDBC 和 iBatis事务管理器的配置

<!-- 配置事务管理器 -->
 <bean id="TransactionManager"
  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
 </bean>

2.3.2、Hibernate3以上事务管理器的配置(先要集成hibernate,再配置事务管理器)

<!-- 集成hibernate --> 
 <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="dataSource"/> 
    <property name="mappingResources"> 
      <list> 
        <value>classpath:product.hbm.xml</value> 
      </list> 
    </property> 
    <property name="hibernateProperties"> 
      <props> 
       <prop key="hibernate.dialect"> 
      </props> 
    </property> 
  </bean> 
 
<!-- 配置Hibernate事务策略 --> 
 <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
        <property name="sessionFactory" ref="sessionFactory"></property> 
 </bean> 

2.3.3、配置tx/aop声明式事务

<!-- 声明一个切面 --> 
<tx:advice id="txAdvice" transaction-manager="txManager"> 
  <tx:attributes> 
   <tx:method name="find*" propagation="REQUIRED" read-only="true"/> 
   <tx:method name="save*" propagation="REQUIRED"/> 
   <tx:method name="update*" propagation="REQUIRED"/> 
   <tx:method name="*" propagation="SUPPORTS" read-only="true" /> 
  </tx:attributes> 
 </tx:advice> 

别的例子,可以进行对比下:

<tx:advice id="userTxAdvice" transaction-manager="TransactionManager">
    <tx:attributes>
      <tx:method name="delete*" propagation="REQUIRED" read-only="false" 
                            rollback-for="Java.lang.Exception" no-rollback-for="java.lang.RuntimeException"/>


      <tx:method name="insert*" propagation="REQUIRED" read-only="false"
                            rollback-for="java.lang.RuntimeException" />


      <tx:method name="update*" propagation="REQUIRED" read-only="false"
                            rollback-for="java.lang.Exception" />
      
      <tx:method name="find*" propagation="SUPPORTS"/>
      <tx:method name="get*" propagation="SUPPORTS"/>
      <tx:method name="select*" propagation="SUPPORTS"/>
    </tx:attributes>
  </tx:advice>
<!-- 把切面注入到业务中 --> 
<aop:config> 
  <aop:pointcut id="productServiceMethods" expression="execution(* com.wzc.student.business.*.*(..))" /> 
  <aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods" /> 
 </aop:config> 

对比:

<aop:config>    
    <aop:pointcut id="pc" expression="execution(public * com.haso.bscsserver.service.*.*(..))" /> <!--把事务控制在Service层-->
    <aop:advisor pointcut-ref="pc" advice-ref="userTxAdvice" />
  </aop:config>

2.4 context:component-scan

<!-- 对包中的所有类进行扫描,以完成Bean创建和自动依赖注入的功能 -->
 <context:component-scan base-package="com.haso.bscsserver">
  <!-- 允许定义过滤器将基包下的某些类纳入或排除
  <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> -->
 </context:component-scan>

2.5 aop注解支持

<!-- aop注解支持 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>

2.6 缓存配置

<!-- 缓存配置 -->
 <bean id="cacheManager"
        class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
     <property name="configLocation" value="/WEB-INF/ehcache.xml"/>
 </bean>
 <!-- A facade to the Ehcache cache class -->
 <bean id="cacheProviderFacade"
         class="org.springmodules.cache.provider.ehcache.EhCacheFacade">
     <property name="cacheManager" ref="cacheManager" />
 </bean>
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>

ehcache.xml文件:

<!--  
    name:Cache的唯一标识  
    maxElementsInMemory:内存中最大缓存对象数  
    maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大  
    eternal:Element是否永久有效,一但设置了,timeout将不起作用  
    overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中 
    timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大 
    timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大  
    diskPersistent:是否缓存虚拟机重启期数据  
    diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒 
    diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区 
     memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)  
    -->  
 <defaultCache overflowToDisk="true" eternal="true"/>
 <diskStore path="C:/cache" />
  <cache name="zzugxy" overflowToDisk="true" eternal="false"  
        timeToIdleSeconds="300" timeToLiveSeconds="600" maxElementsInMemory="1000" 
        maxElementsOnDisk="10" diskPersistent="true" diskExpiryThreadIntervalSeconds="300" 
        diskSpoolBufferSizeMB="100" memoryStoreEvictionPolicy="LRU" />  
</ehcache>

2.7

<!-- Spring、MyBatis的整合,需要在 Spring 应用上下文中定义至少两样东西:一个SqlSessionFactory和至少一个数据映射器类(UserMapper->iocContext.xml)。 -->
 
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"


   p:dataSource-ref="dataSource" p:configLocation="classpath:mybatis-config.xml"


   p:mapperLocations="classpath:com/demo/dao/*.xml" />


<!-- spring与mybatis整合配置,扫描所有dao -->


<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"


   p:basePackage="com.demo.dao" p:sqlSessionFactoryBeanName="sqlSessionFactory" />

参考(出自http://blog.csdn.net/snn1410/article/details/7846582)

三.springMVC配置文件:

SpringMVC是一个基于DispatcherServlet的MVC框架,每一个请求最先访问的都是DispatcherServlet,DispatcherServlet负责转发每一个Request请求给相应的Handler,Handler处理以后再返回相应的视图(View)和模型(Model),返回的视图和模型都可以不指定,即可以只返回Model或只返回View或都不返回。

DispatcherServlet是继承自HttpServlet的,既然SpringMVC是基于DispatcherServlet的,那么我们先来配置一下DispatcherServlet,好让它能够管理我们希望它管理的内容。HttpServlet是在web.xml文件中声明的。

 

服务器启动时会主动扫描WEB-INF下面且名字是XXX-servlet.xml配置文件,如果在WEB-INF下配置且名字为XXX-servlet.xml,就可以不用配置在web.xml里.否则需要在web.xml中配置springMVC文件.

在web.xml中配置springMVC文件方式:

 

	在<servlet-mapping>中url如果是.action,前端控制器就只会拦截以.action结尾的请求,并不会理会静态的文件。对静态页面的控制就要通过其他的手段。以/作为url的话就会拦截所有的请求,包括静态页面的请求。这样的话就可以拦截任何想要处理的请求,但是有一个问题。如果拦截了所有的请求,如果不在拦截器中做出相应的处理那么所有静态的js、css以及页面中用到的图片就会访问不到造成页面无法正常显示。

 

 

<!-- Spring MVC配置 -->

<!-- ====================================== -->
<servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 可以自定义servlet.xml配置文件的位置和名称,默认为WEB-INF目录下,名称为[<servlet-name>]-servlet.xml,如spring-servlet.xml
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-servlet.xml</param-value>&nbsp; 默认
    </init-param>
    -->
 
    <init-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>classpath:config/spring-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
 
<span style="color:#888888"><!-- 1、.do访问以.do结尾的  由DispatcherServlet进行解析
     2、/,所有访问都由DispatcherServlet进行解析--></span>

<servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>*.do</url-pattern></servlet-mapping> <!-- Spring配置 --><!-- ====================================== --><listener> <listenerclass> org.springframework.web.context.ContextLoaderListener </listener-class></listener> <!-- 指定Spring Bean的配置文件所在目录。默认配置在WEB-INF目录下 --><context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:config/applicationContext.xml</param-value></context-param>

 

 

上面提到过如果在配置前端控制器时拦截了所有的请求,不做特殊处理就会导致部分静态资源无法使用。如果是这种情况就可以使用下面的配置来访问静态资源文件。

 
<mvc:resources mapping="/images/**" location="/images/" />
<mvc:resources mapping="/css/**" location="/css/" />  
<mvc:resources mapping="/js/**" location="/js/" />
<mvc:resources mapping="/imgdata/**" location="/imgdata/" />
<!--也可以使用默认,但是需要在web.xml中配置。-->
<!-- 访问静态资源文件 -->
    <!-- <mvc:default-servlet-handler/> 需要在web.xml中配置-->

 spring-servlet.xml配置

  spring-servlet这个名字是因为上面web.xml中<servlet-name>标签配的值为spring(<servlet-name>spring</servlet-name>),再加上“-servlet”后缀而形成的spring-servlet.xml文件名,如果改为springMVC,对应的文件名则为springMVC-servlet.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:p="http://www.springframework.org/schema/p"     
        xmlns:context="http://www.springframework.org/schema/context"     
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd   
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd   
       http://www.springframework.org/schema/context <a href="http://www.springframework.org/schema/context/spring-context-3.0.xsd">http://www.springframework.org/schema/context/spring-context-3.0.xsd</a>">

    <!-- 启用spring mvc 注解 -->
    <context:annotation-config />

    <!-- 设置使用注解的类所在的jar包 -->
    <context:component-scan base-package="controller"></context:component-scan>

    <!-- 完成请求和注解POJO的映射 -->
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
  
    <!-- 视图解析器 --对转向页面的路径解析。prefix:前缀, suffix:后缀 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/jsp/" p:suffix=".jsp" />
 
   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/jsp/">
	<property name="suffix" value=".jsp"/> 
   </bean>

 

DispatcherServlet会利用一些特殊的bean来处理Request请求和生成相应的视图返回。

关于视图的返回,Controller只负责传回来一个值,然后到底返回的是什么视图,是由视图解析器控制的,在jsp中常用的视图解析器是InternalResourceViewResovler,它会要求一个前缀和一个后缀

在上述视图解析器中,如果Controller返回的是blog/index,那么通过视图解析器解析之后的视图就是/jsp/blog/index.jsp。

 

主要是说说Controller.

一个类使用了@Controller进行标记的都是Controller

package controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import entity.User;

@Controller  //类似Struts的Action
public class TestController {

    @RequestMapping("test/login.do")  // 请求url地址映射,类似Struts的action-mapping
    public String testLogin(@RequestParam(value="username")String username, String password, HttpServletRequest request) {
        // @RequestParam是指请求url地址映射中必须含有的参数(除非属性required=false)
        // @RequestParam可简写为:@RequestParam("username")

        if (!"admin".equals(username) || !"admin".equals(password)) {
            return "loginError"; // 跳转页面路径(默认为转发),该路径不需要包含spring-servlet配置文件中配置的前缀和后缀
        }
        return "loginSuccess";
    }

    @RequestMapping("/test/login2.do")
    public ModelAndView testLogin2(String username, String password, int age){
        // request和response不必非要出现在方法中,如果用不上的话可以去掉
        // 参数的名称是与页面控件的name相匹配,参数类型会自动被转换
        
        if (!"admin".equals(username) || !"admin".equals(password) || age < 5) {
            return new ModelAndView("loginError"); // 手动实例化ModelAndView完成跳转页面(转发),效果等同于上面的方法返回字符串
        }
        return new ModelAndView(new RedirectView("../index.jsp"));  // 采用重定向方式跳转页面
        // 重定向还有一种简单写法
        // return new ModelAndView("redirect:../index.jsp");
    }

    @RequestMapping("/test/login3.do")
    public ModelAndView testLogin3(User user) {
        // 同样支持参数为表单对象,类似于Struts的ActionForm,User不需要任何配置,直接写即可
        String username = user.getUsername();
        String password = user.getPassword();
        int age = user.getAge();
        
        if (!"admin".equals(username) || !"admin".equals(password) || age < 5) {
            return new ModelAndView("loginError");
        }
        return new ModelAndView("loginSuccess");
    }

    @Resource(name = "loginService")  // 获取applicationContext.xml中bean的id为loginService的,并注入
    private LoginService loginService;  //等价于spring传统注入方式写get和set方法,这样的好处是简洁工整,省去了不必要得代码

    @RequestMapping("/test/login4.do")
    public String testLogin4(User user) {
        if (loginService.login(user) == false) {
            return "loginError";
        }
        return "loginSuccess";
    }
}

 

 

以上4个方法示例,是一个Controller里含有不同的请求url,也可以采用一个url访问,通过url参数来区分访问不同的方法,代码如下:

package controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/test2/login.do")  // 指定唯一一个*.do请求关联到该Controller
public class TestController2 {
    
    @RequestMapping
    public String testLogin(String username, String password, int age) {
        // 如果不加任何参数,则在请求/test2/login.do时,便默认执行该方法
        
        if (!"admin".equals(username) || !"admin".equals(password) || age < 5) {
            return "loginError";
        }
        return "loginSuccess";
    }

    @RequestMapping(params = "method=1", method=RequestMethod.POST)
    public String testLogin2(String username, String password) {
        // 依据params的参数method的值来区分不同的调用方法
        // 可以指定页面请求方式的类型,默认为get请求
        
        if (!"admin".equals(username) || !"admin".equals(password)) {
            return "loginError";
        }
        return "loginSuccess";
    }
    
    @RequestMapping(params = "method=2")
    public String testLogin3(String username, String password, int age) {
        if (!"admin".equals(username) || !"admin".equals(password) || age < 5) {
            return "loginError";
        }
        return "loginSuccess";
    }
}

 

 其实RequestMapping在Class上,可看做是父Request请求url,而RequestMapping在方法上的可看做是子Request请求url,父子请求url最终会拼起来与页面请求url进行匹配,因此RequestMapping也可以这么写:

package controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/test3/*")  // 父request请求url
public class TestController3 {

    @RequestMapping("login.do")  // 子request请求url,拼接后等价于/test3/login.do
    public String testLogin(String username, String password, int age) {
        if (!"admin".equals(username) || !"admin".equals(password) || age < 5) {
            return "loginError";
        }
        return "loginSuccess";
    }
}

 

在SpringMVC中常用的注解还有@PathVariable,@RequestParam,@PathVariable标记在方法的参数上,利用它标记的参数可以利用请求路径传值,看下面一个例子

@RequestMapping(value="/comment/{blogId}", method=RequestMethod.POST)
public void comment(Comment comment,@PathVariable int blogId, HttpSession session, HttpServletResponse response) throws IOException {
    
}

 

在该例子中,blogId是被@PathVariable标记为请求路径变量的,如果请求的是/blog/comment/1.do的时候就表示blogId的值为1. 同样@RequestParam也是用来给参数传值的,但是它是从头request的参数里面取值,相当于request.getParameter("参数名")方法。

在Controller的方法中,如果需要WEB元素HttpServletRequest,HttpServletResponse和HttpSession,只需要在给方法一个对应的参数,那么在访问的时候SpringMVC就会自动给其传值,但是需要注意的是在传入Session的时候如果是第一次访问系统的时候就调用session会报错,因为这个时候session还没有生成。

 

四.spring与springMVC配置文件讨论

 

在web.xml中定义的spring的配置文件一般有两个: 

1、Spring上下文环境的配置文件:applicationContext.xml

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:applicationContext.xml
        </param-value>
    </context-param>
 

2、SpringMVC配置文件:spring-servlet.xml

    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

加载顺序是:首先加载Spring上下文环境配置文件,然后加载SpringMVC配置文件,并且如果配置了相同的内容,SpringMVC配置文件会被优先使用。 
所以这里需要注意一个问题,一定要注意SpringMVC配置文件内容不要把Spring上下文环境配置文件内容覆盖掉。 
比如在Spring上下文环境配置文件中先引入service层,然后又加入了事务:

    <context:component-scan base-package="com.acms.service"></context:component-scan>
    <!-- define the transaction manager -->
    <bean id="transactionManagerOracle"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSourceOracle" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManagerOracle" />

 

但是在SpringMVC配置文件中却默认引入所有类(当然也包括service层),但是没有加入事务

    <context:component-scan base-package="com.acms"></context:component-scan>

那么这时事务功能是无法起作用的,也就是代码中加入@Transactional注解是无效的。

所以为了防止这种问题一般是在Spring上下文配置文件中引入所有的类,并且加上事务:

    <context:component-scan base-package="com.acms"></context:component-scan>
    <!-- define the transaction manager -->
    <bean id="transactionManagerOracle"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSourceOracle" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManagerOracle" />

 

而在SpringMVC配置文件中只引入controller层:

    <context:component-scan base-package="com.acms.controller" />
    <context:component-scan base-package="com.acms.*.controller" />

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值