Spring MVC快速上手教程


Spring Framework可以被使用在很多場合之中,考慮到目前大多數Java EE的項目是B/S結構的,所以這裏的快速上手教程會以Spring MVC爲切入點,用最簡單的代碼一步一步來實現一個圖書列表的頁面。

在正式動手之前需要做一些準備工作,先安裝並設置好JDK 1.5和Tomcat 5,關於數據庫及其訪問方式可以根據個人習慣進行選擇,教程中使用MySQL數據庫和Hibernate(映射由Hibernate Annotation實現)。請將實際使用到的jar文件複製到WEB-INF/lib目錄中,整個項目的結構見圖1,教程中用到的jar文件見圖2。

結構及用到的Jar文件

項目中的Bean定義分散在多個XML文件中,每完成一部分代碼就給出相應的配置,最後再進行整合和部署。配置中使用default-autowire="byName"實現了Bean的自動織入,節省了很多個工作量,只需注意Bean及屬性的命名即可。

Step 1.Business Objects & DAO

教程中的例子涉及到兩個實體對象,代表文章的Article類和代表作者的Author類,分別對應了數據庫中的article表和author表,一篇文章有一個作者,而一個作者可以有多篇文章。類的代碼如下(省略getter和setter):

代碼:Article.java

package demo.model;

import javax.persistence.*;

@Entity
public class Article {
    @Id
    @GeneratedValue
    
private Long id;
    
    
private String title;
    
    @ManyToOne
    
private Author author;
    
}

代碼:Author.java

package demo.model;

import java.util.List;
import javax.persistence.*;

@Entity
public class Author {
    @Id
    @GeneratedValue
    
private Long id;
    
    
private String name;
    
    @OneToMany
    
private List<Article> articles;
    
}

在MySQL中創建數據表的SQL語句如下,數據請自行添加(如果使用Hibernate,表可以根據映射自動生成,具體做法請參考Hibernate文檔):

代碼:數據庫創建SQL

CREATE DATABASE `articles` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE articles;

CREATE TABLE `article` (
  `id` 
bigint(20NOT NULL auto_increment,
  `title` 
varchar(100NOT NULL default '',
  `author_id` 
bigint(20NOT NULL default '0',
  
PRIMARY KEY  (`id`)
) ENGINE
=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `author` (
  `id` 
bigint(20NOT NULL auto_increment,
  `name` 
varchar(100NOT NULL default '',
  
PRIMARY KEY  (`id`)
) ENGINE
=MyISAM DEFAULT CHARSET=utf8;

考慮到可能會有多種DAO的實現,所以在DAO層先定義一個IArticleDao接口,隨後可以自由選擇具體的實現方式,此處結合Spring的HibernateDaoSupport使用Hibernate來進行實現:

代碼:IArticleDao.java

package demo.dao;

import java.util.List;

import demo.model.Article;

public interface IArticleDao {
    
public List<Article> loadAllArticles();
}

代碼:ArticleDao.java

package demo.dao;

import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import demo.model.Article;

public class ArticleDao extends HibernateDaoSupport implements IArticleDao {

    @SuppressWarnings(
"unchecked")
    
public List<Article> loadAllArticles() {
        
return (List<Article>)getHibernateTemplate().loadAll(Article.class);
    }


}

接下來對Hibernate進行相應的配置,如果使用了JDO或者iBatis,請參考Spring文檔。applicationContext-dao.xml內容如下:

代碼:applicationContext-dao.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.0.xsd"
    default-autowire
="byName">
    
<!-- DAO配置於此 -->
    
<bean id="articleDao" class="demo.dao.ArticleDao"/>
    
    
<!-- 數據源 -->
    
<!-- JNDI數據源 -->
    
<!-- 
    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="${datasource.jndi.name}"/>
    </bean>
    
-->
     
    
<!-- JDBC數據源 -->
    
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        
<property name="driverClassName" value="${datasource.jdbc.driverClassName}" />
        
<property name="url" value="${datasource.jdbc.url}" />
        
<property name="username" value="${datasource.jdbc.username}" />
        
<property name="password" value="${datasource.jdbc.password}" />
    
</bean>
    
    
<!-- 使用Annotation映射的sessionFactory -->
    
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        
<property name="dataSource" ref="dataSource"/>
        
<property name="hibernateProperties">
            
<props>
                
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
                
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                
<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
                
<prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop>
            
</props>
        
</property>
        
<property name="annotatedClasses">
            
<list>
                
<value>demo.model.Article</value>
                
<value>demo.model.Author</value>
            
</list>
        
</property>
    
</bean>

    
<!-- 事務管理器,此處爲Hibernate的事務管理器 -->
    
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" />    
</beans>

此處如果使用JNDI提供數據源,請根據註釋進行調整。Spring的事務管理需要聲明事務管理器,由於Hibernate、JDO、JDBC的事 務管理器都不一樣,所以將其與其他事務的配置分開存放。此外,配置中的一些參數使用了佔位符(形如${}),這些內容將在Step 4中進行加載。

Step 2.Service

Service層只是調用DAO中的方法爲控制器提供圖書列表,Service最好能先給出接口,隨後進行實現,但此處的功能比較簡單,就直接進行實現了:

代碼:ArticleService.java

package demo.service;

import java.util.List;
import demo.dao.IArticleDao;
import demo.model.Article;

public class ArticleService {
    
private IArticleDao articleDao;
    
    
public List<Article> loadAllArticles() {
        
return articleDao.loadAllArticles();
    }


    
public void setArticleDao(IArticleDao articleDao) {
        
this.articleDao = articleDao;
    }

}

Spring通過setArticleDao方法爲ArticleService注入DAO,也可以選擇通過構造方法注入,2.5中還能用@Autowired進行注入。

applicationContext-services.xml內容如下:

代碼:applicationContext-services.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.0.xsd"
    default-autowire
="byName">
    
<!-- Service配置於此 -->
    
<bean id="articleService" class="demo.service.ArticleService" />
</beans>

Step 3.Controller & View

Spring MVC提供了多種實現控制器的方式,此處直接實現Controller接口,開發一個單一動作的簡單控制器,從Service中取得圖書列表,提供給視圖進行呈現,ListArticleController內容如下:

代碼:ListArticleController.java

package demo.controller;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import demo.model.Article;
import demo.service.ArticleService;

public class ListArticleController implements Controller {
    
private ArticleService articleService;
    
    
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        List
<Article> articles = articleService.loadAllArticles();
        ModelAndView mav 
= new ModelAndView();
        mav.addObject(articles);
        
return mav;
    }


    
public void setArticleService(ArticleService articleService) {
        
this.articleService = articleService;
    }

}

ModelAndView中保存了要傳遞給視圖的對象和具體要使用的視圖文件,自2.0起, Spring MVC提供了Convention over Configuration的機制,大大簡化了代碼與配置。簡單地說,名字以Controller結尾的控制器類都會被映射爲相應的地址, ListArticleController對應/listarticle*,如果是MultiActionController則會被映射爲一個目錄; 向ModelAndView添加對象時可以不用指定鍵(key),單一對象的鍵取決於類名,比如x.y.User的鍵是user,而某一類對象的Set、 List或數組則稍有些複雜,取第一個對象的類名加上“List”作爲它的鍵,比如這裏的articles是一個存放Article對象的List,它的 鍵就是articleList;具體的視圖會根據請求自動在指定目錄中尋找對應的視圖文件,本例中就會尋找listarticle(後綴由配置文件決 定)。關於Convention over Configuration還有些別的細節,請參考Spring文檔的相關章節。

此處的視圖比較簡陋,只是一張表格,顯示了圖書的編號、書名和作者,使用JSTL的<c:forEach>標籤來遍歷列表,具體代碼如下:

代碼:listarticle.jsp

<%@ page pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
    
<head>
        
<title>Article List</title>
    
</head>
    
<body>
        
<table width="80%" cellspacing="0" cellpadding="0" border="1">
            
<thead>
                
<tr align="center">
                    
<td width="20%">編號</td><td width="50%">書名</td><td width="30%">作者</td>
                
</tr>
            
</thead>
            
<tbody>
            
<c:forEach items="${articleList}" var="article">
                
<tr>
                    
<td align="center">${article.id}</td>
                    
<td>${article.title}</td>
                    
<td>${article.author.name}</td>
                
</tr>
            
</c:forEach>
            
</tbody>
        
</table>
    
</body>
</html>

爲了使用Spring MVC,需要在web.xml中配置一個分派器,將一些特定格式的請求交給Spring MVC來處理(其實就是一個Servlet,這和Struts有些類似),如果它的名字是dispatcher,那麼Spring默認會去尋找名爲 dispatcher-servlet.xml的配置文件,該文件內容如下:

代碼:dispatcher-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"
    xsi:schemaLocation
="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"
    default-autowire
="byName">
    
<!-- SpringMVC相關Bean配置 -->

    
<!-- View Resolver -->
    
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        
<property name="prefix" value="/WEB-INF/view/" />
        
<property name="suffix" value=".jsp" />
    
</bean>

    
<bean id="viewNameTranslator" class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator"/>
    
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>

    
<!-- 以下爲Controller -->
    
<bean id="listArticleController" class="demo.controller.ListArticleController" />
    
</beans>

配置中的DefaultRequestToViewNameTranslator和 ControllerClassNameHandlerMapping就是用來實現Convention over Configuration的,而名爲viewResolver的Bean則指定了一些視圖的信息。

Step 4.Configuration & Deployment

至此,大部分的工作已經完成了,接下來就是加載properties文件和配置事務屬性,這些都放在applicationContext.xml中:

代碼: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"
    xmlns:aop
="http://www.springframework.org/schema/aop"
    xmlns:tx
="http://www.springframework.org/schema/tx"
    xsi:schemaLocation
="
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"
>
    
    
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        
<property name="locations">
            
<list>
                
<value>classpath:config.properties</value>
            
</list>
        
</property>
    
</bean>

    
<!-- 事務 -->
    
<tx:advice id="txAdvice">
        
<tx:attributes>
            
<tx:method name="get*" read-only="true" />
            
<tx:method name="find*" read-only="true" />
            
<tx:method name="load*" read-only="true" />
            
<tx:method name="*" />
        
</tx:attributes>
    
</tx:advice>
    
    
<aop:config proxy-target-class="true">
        
<aop:advisor advice-ref="txAdvice" pointcut="execution(* demo.service..*.*(..))" />
    
</aop:config>
</beans>

pointcut屬性確定了AOP攔截的方法,用的是AspectJ pointcut expression,此處對demo.service中每一個類的所有方法都進行了攔截,也就是它們都在事務中執行。

config.properties中保存了一些與數據庫和Hibernate相關的配置信息,它們會代替XML中對應的佔位符:

代碼:config.properties

# DataSource
# JNDI datasource Eg. java:comp/env/jdbc/myds
datasource.jndi.name
=
# JDBC datasource
datasource.jdbc.driverClassName
=com.mysql.jdbc.Driver
datasource.jdbc.url
=jdbc:mysql://localhost/articles?useUnicode=true&characterEncoding=utf8
datasource.jdbc.username
=root
datasource.jdbc.password
=

# Hibernate
hibernate.dialect
=org.hibernate.dialect.MySQLDialect
hibernate.show_sql
=false
hibernate.cache.use_query_cache
=true
hibernate.cache.provider_class
=org.hibernate.cache.EhCacheProvider

最後要看到的就是web.xml,每個Java EE的Web項目都會有這個配置文件,具體內容如下:

代碼:web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 
    xmlns
="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation
="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
>
    
    
<!-- Spring ApplicationContext配置文件的路徑可使用通配符,多個路徑用,號分隔,此參數用於後面的Spring-Context loader -->
    
<context-param>
        
<param-name>contextConfigLocation</param-name>
        
<param-value>/WEB-INF/modules/applicationContext*.xml</param-value>
    
</context-param>
    
    
<!-- SpringMVC 分派器及相關映射 -->
    
<servlet>
        
<servlet-name>dispatcher</servlet-name>
        
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        
<load-on-startup>1</load-on-startup>
    
</servlet>
    
    
<servlet-mapping>
        
<servlet-name>dispatcher</servlet-name>
        
<url-pattern>*.html</url-pattern>
    
</servlet-mapping>

    
<servlet-mapping>
        
<servlet-name>dispatcher</servlet-name>
        
<url-pattern>*.do</url-pattern>
    
</servlet-mapping>

    
<!--Spring ApplicationContext 載入 -->
    
<listener>
        
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    
</listener>
    
    
<!-- Spring 刷新Introspector防止內存泄露 -->
    
<listener>
        
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    
</listener>
    
    
<!-- 支持session scope的Spring bean -->
    
<listener>                                                        
         
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    
</listener>

    
<!-- Character Encoding filter -->
    
<filter>
        
<filter-name>setCharacterEncoding</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>setCharacterEncoding</filter-name>
        
<url-pattern>/*</url-pattern>
    
</filter-mapping>
    
    
<!--Hibernate Open Session in View Filter-->
    
<filter>
      
<filter-name>hibernateFilter</filter-name>
      
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
     
</filter>
     
    
<filter-mapping>
        
<filter-name>hibernateFilter</filter-name>
        
<url-pattern>/*</url-pattern>
    
</filter-mapping>
</web-app>

此處加載了Spring的配置文件,並對字符編碼進行了處理,*.do和*.html的請求都轉交給了Spring MVC的分派器。OpenSessionInViewFilter是用來解決Hibernate的OpenSessionInView問題的,如果沒有使 用Hibernate則無需配置此過濾器。

項目的部署和一般的Web項目沒有任何區別,將項目打成War包或者直接將目錄放到Tomcat的webapps中即可。假設目錄的名字是SpringDemo,啓動Tomcat後訪問http://localhost:8080/SpringDemo/listarticle.html就能看到頁面的效果了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章