50
專案:Spring 線上書Spring Spring API Spring Web Spring Web MVC Spring IoC Hibernate Java Mail View JSP Spring JSTL Spring Spring 10

Spring 2.0 技術手冊第十章 - 專案:線上書籤

Embed Size (px)

DESCRIPTION

Spring 2.0 技術手冊

Citation preview

Page 1: Spring 2.0 技術手冊第十章 - 專案:線上書籤

專案:Spring線上書籤

在先前的各章節中,著重於介紹 Spring 的各個功能,並在一些簡單的應用程式中,突顯 Spring 中各種 API 的使用與組態設定方式。 在這個章節中,將組合先前介紹過的 Spring 功能,完成一個可以線上管理書籤的 Web 程式,程式中將使用 Spring Web MVC 框架、Spring IoC 容器、Hibernate 以及 Java Mail 等,在 View 層技術上則使用 JSP、Spring 標籤與 JSTL,藉由實際完成 Spring 線上書籤,您可以了解到如何使用 Spring 來開發專案。

10

Page 2: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��2

10.1 程式概觀 在正式開始設計程式之前,先花一些時間來設計程式的架構與考慮所要採用的技術,雖然這只是一個簡單的 Web程式,但事前一些簡單的紙上作業,可以避免程式開發過程中,因架構不清楚而造成的程式混亂或不必要的修改。

10.1.1 架構規劃

Spring線上書籤將採用 Web MVC的架構來設計程式,基於 Web MVC架構的流程,規劃出以下的流程架構:

圖 10.1 Spring 線上書籤流程架構

Page 3: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��3

對於圖中每個流程與圖示的作用,稍微作個說明:

� 前端控制器(Front Controller) 在 Spring線上書籤中,採用前端控制器來接受使用者的請求,使用者在“流程 1”中向前端控制器發送請求,前端控制器將決定由哪一個控制器來處理請求。

� 控制器 前端控制器決定好控制器後,在“流程 2”中將請求交由控制器來處理,控制器將擷取使用者的請求參數、進行資料驗證,並呼叫商務層的物件來完成請求。

� Data、Mail、DAO 等 Model 物件 在請求中有一些業務必須調用業務層中的 Model 物件來處理,控制器在“流程 3”中調用資料存取物件(DAO)、Mail 商務物件等來處理這些請求,如果需要的話,還可以將一些訊息封裝為資料(Data)物件。

� 資料庫

Spring 線上書籤程式中用來儲存書籤的媒介將採用資料庫,在“流程 4”中資料存取物件將負責與資料庫進行儲存、查詢、更新等動作。

� 網頁 在處理流程返回至控制器之後,控制器收集必要的訊息並設定為網頁所 可以存取的資料物件,接著在“流程 5”中轉發給呈現結果畫面的網頁,網頁會擷取必要的資料物件並顯示畫面,在“流程 6”中將結果傳回給使用者。

Page 4: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��4

10.1.2 採用技術 在了解大致的程式架構之後,來考慮每一個環節將實際採用的技術。

� 前端控制器(Front Controller) 在 Spring 線上書籤中,將使用 Spring 的 Web MVC 框架來實現 Web MVC架構,其中所採用的前端控制器為 Spring 的 DispatcherServlet 類別。

� 控制器 由於採用 Spring Web MVC 框架,配合 Spring 的 DispatcherServlet 類別,將使用 Spring Web MVC 中 Controller 繼承架構上的類別,例如 Abstract-

CommandController、SimpleFormController、MultiActionController 等類別。

� Data、Mail、DAO 等 Model 物件 資料物件方面為自訂的 User 類別與 Bookmark 類別,在 DAO 物件的實現上,將採用 Hibernate 來自動進行物件 /關係映射(Object/Relational

Mapping),在資料存取的過程中,將會使用到 User、Bookmark 類別作為資料物件,而程式中會有發送郵件的需求,這個部份使用到 Java Mail的功能,會使用 Spring 的 Java Mail 抽象層封裝。

� 資料庫

Spring 線上書籤用來儲存使用者資料與書籤的媒介,將採用 MySQL 關聯式資料庫。

� 網頁 在網頁技術的採用上,使用 JSP 技術為基礎,運用 Spring 的一些綁定標籤,並使用 JSTL 來處理頁面邏輯的呈現。

Page 5: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1���

10.1.3 功能概述 在 Spring線上書籤,可以讓您進行線上書籤管理,您可以註冊一個新的使用者,並擁有自己的書籤管理頁面,可以在管理頁面中進行書籤的新增與刪除動作,或者是變更您的密碼,如果忘記密碼的話,還可以輸入註冊時的郵件位址,讓系統發一封信件告知您的使用者密碼。 在這邊先不列出程式執行的畫面,程式執行的畫面可以在稍後的小節中設計相關頁面時看到。 基於篇幅的限制,這個程式示範的,僅是如何組合相關的框架或API 來完成一個程式,程式中的一些功能並沒有設計的面面俱到,這個程式主要目的是教學之用,如果您打算實際在某些場合使用這個程式,必須自行修改、完備這個程式。

Page 6: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��6

10.2 Model設計 在 Spring線上書籤的設計中,商務層的 Model物件有負責與資料庫進行存取的 UserDAO、BookmarkDAO,分別負責存取使用者資料與書籤資料,而在使用者忘記密碼時,必須使用到郵件功能寄送使用者的密碼,這將設計一個 SimpleMail類別來完成這個功能。

10.2.1 UserDAO 對於使用者資料的儲存,程式中設計有一個 User類別,用以對應資料庫表格中的 user表格,來看一下 User類別的撰寫:

SpringBookmark User.java

package onlyfun.caterpillar.model;

public class User {

private Integer id;

private String email;

private String username;

private String passwd;

public void setId(Integer id) {

this.id = id;

}

public Integer getId() {

return id;

}

public void setEmail(String email) {

this.email = email;

}

public void setUsername(String username) {

this.username = username;

}

Page 7: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��7

public void setPasswd(String passwd) {

this.passwd = passwd;

}

public String getEmail() {

return email;

}

public String getUsername() {

return username;

}

public String getPasswd() {

return passwd;

}

} 可以看到 User 物件中將包括使用者的名稱、密碼與郵件位址,其中

"id" 屬性是在運用 Hibernate時所需的唯一識別,這個 User類別將對應於資料庫中的 user表格,可以使用以下的 SQL來建立 user表格:

CREATE TABLE user (

id INT(11) NOT NULL auto_increment PRIMARY KEY,

username VARCHAR(16),

passwd CHAR(16) NOT NULL,

email VARCHAR(100) NOT NULL

); 在 UserDAO的實作上,將使用 Hibernate進行物件關係映射,為了映射 User類別與 user表格,需要撰寫一個 User.hbm.xml,如下所示:

SpringBookmark User.hbm.xml

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

<!DOCTYPE hibernate-mapping

PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

Page 8: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��8

<hibernate-mapping>

<class name="onlyfun.caterpillar.model.User"

table="user">

<id name="id" column="id">

<generator class="native"/>

</id>

<property name="username" column="username"/>

<property name="passwd" column="passwd"/>

<property name="email" column="email"/>

</class>

</hibernate-mapping> 為了不讓應用程式依賴於實際的 DAO 實作類別,可以透過設計一個IUserDAO介面,讓應用程式依賴於介面,介面設計如下:

SpringBookmark IUserDAO.java

package onlyfun.caterpillar.model;

public interface IUserDAO {

public void insert(User user);

public User findByName(String username);

public User findByEmail(String email);

public void update(User user);

} 在 IUserDAO中,可以根據 User物件來進行資料的儲存與更新,並也可以分別根據使用者的名稱,或是使用者的郵件位址來查詢 User資料,在IUserDAO介面的實作類別 UserDAO的設計上,如下所示:

SpringBookmark UserDAO.java

package onlyfun.caterpillar.model;

import java.util.List;

import org.springframework.orm.hibernate3.HibernateTemplate;

Page 9: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1���

public class UserDAO implements IUserDAO {

private HibernateTemplate hibernateTemplate;

public void setHibernateTemplate(

HibernateTemplate hibernateTemplate) {

this.hibernateTemplate = hibernateTemplate;

}

public void insert(User user) {

hibernateTemplate.saveOrUpdate(user);

}

public User findByName(String username) {

if(username.equals("")) {

return null;

}

List users = hibernateTemplate.find(

"from User user where user.username='"

+ username + "'");

return (User) users.get(0);

}

public User findByEmail(String email) {

List users = hibernateTemplate.find(

"from User user where user.email='"

+ email + "'");

return (User) users.get(0);

}

public void update(User user) {

hibernateTemplate.update(user);

}

}

Page 10: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��1�

在 HibernateTemplate 的 find()方法中看到的是 Hibernate

Query Language,簡稱 HQL,為 Hibernate 所鼓勵使用的查詢語言,在使用上比 SQL 簡單且具有物件導向語言的特性,可以參考我的網站中有關 HQL 的介紹:

http://caterpillar.onlyfun.net/Gossip/HibernateGossip/

HibernateGossip.html 在 Spring 線上書籤中,使用 Spring 對 Hibernate 的封裝來運用Hibernate(參考第 6 章的內容),這邊使用 HibernateTemplate 物件來進行各種資存取、查詢、更新操作,HibernateTemplate 物件將使用 Spring的依賴注入功能來注入實例,稍後可以看到組態檔案中會進行相關的設定。

10.2.2 BookmarkDAO 對於書籤資料的儲存,程式中設計有一個 Bookmark 類別,用以對應資料庫表格中的 bookmark表格,來看一下 Bookmark類別的撰寫:

SpringBookmark Bookmark.java

package onlyfun.caterpillar.model;

public class Bookmark {

private Integer id;

private String username;

private String url;

public void setId(Integer id) {

this.id = id;

}

public Integer getId() {

return id;

}

Page 11: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��11

public void setUsername(String username) {

this.username = username;

}

public String getUrl() {

return url;

}

public void setUrl(String url) {

this.url = url;

}

public String getUsername() {

return username;

}

} 可以看到 Bookmark 物件中將包括書籤的擁有者名稱與書籤網址,其中 "id" 屬性是在運用 Hibernate時所需的唯一識別,這個 Bookmark類別將對應於資料庫中的 bookmark 表格,可以使用以下的 SQL 來建立bookmark表格:

CREATE TABLE bookmark (

id INT(11) NOT NULL auto_increment PRIMARY KEY,

username VARCHAR(16) NOT NULL,

bm_URL VARCHAR(255) NOT NULL

);

實際上,user 表格與 bookmark 表格可以建立為一對多關係,不過由於這本書中並沒有介紹到 Hibernate 中如何映射一對多關係,因而範例仍設計為兩個獨立的表格。

Page 12: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��12

在 BookmarkDAO 的實作上,將使用 Hibernate 進行物件關係映射,為了映射 Bookmark 類別與 bookmark 表格,需要撰寫一個 Bookmark.

hbm.xml,如下所示:

SpringBookmark Bookmark.hbm.xml

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

<!DOCTYPE hibernate-mapping

PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name="onlyfun.caterpillar.model.Bookmark"

table="bookmark">

<id name="id" column="id">

<generator class="native"/>

</id>

<property name="username" column="username"/>

<property name="url" column="bm_URL"/>

</class>

</hibernate-mapping> 為了不讓應用程式依賴於實際的DAO實作類別,可以設計一個 IBook-

markDAO介面,讓應用程式依賴於介面,介面設計如下:

SpringBookmark IBookmarkDAO.java

package onlyfun.caterpillar.model;

import java.util.List;

public interface IBookmarkDAO {

public List findUserUrl(String username);

public void addUserUrl(String username, String url);

public void deleteUserUrls(String username, String[] urls);

}

Page 13: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��13

在 IBookmarkDAO中,規範的方法有:根據使用者名稱與提供的書籤URL來增加書籤資料,根據使用者名稱來查詢書籤資料,進行書籤的刪除。在 IBookmarkDAO介面的實作類別 BookmarkDAO的設計上,如下所示:

SpringBookmark BookmarkDAO.java

package onlyfun.caterpillar.model;

import java.util.List;

import org.springframework.orm.hibernate3.HibernateTemplate;

public class BookmarkDAO implements IBookmarkDAO {

private HibernateTemplate hibernateTemplate;

public void setHibernateTemplate(

HibernateTemplate hibernateTemplate) {

this.hibernateTemplate = hibernateTemplate;

}

public List findUserUrl(String username) {

List list= hibernateTemplate.find(

"select bm.url from Bookmark as bm where bm.username='"

+ username + "'");

return list;

}

public void addUserUrl(String username, String url) {

Bookmark bm = new Bookmark();

bm.setUsername(username);

bm.setUrl(url);

hibernateTemplate.saveOrUpdate(bm);

}

public void deleteUserUrls(

String username, String[] urls) {

for(int i = 0; i < urls.length; i++) {

List list = hibernateTemplate.find(

"from Bookmark bm where (bm.username='"

+ username +

"') and (bm.url='" + urls[i]+ "')");

hibernateTemplate.delete(list.get(0));

Page 14: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��14

}

}

} 同樣的在 BookmarkDAO的實作中,使用 Spring對 Hibernate的封裝來運用 Hibernate,HibernateTemplate物件也將使用 Spring的依賴注入功能來注入實例,稍後可以看到組態檔案中會進行相關的設定。

10.2.3 SimpleMail 當使用者忘記登入時所使用的密碼時,可以要求他輸入註冊時所使用的 Email位址,以查詢使用者的密碼,程式會寄送郵件告知密碼,郵件的寄送在程式中使用 Java Mail來完成,並運用 Spring對 Java Mail的封裝,以簡化程式的撰寫(參考 9.2.1),這個部份比較簡單,來看一下 SimpleMail類別的設計:

SpringBookmark SimpleMail.java

package onlyfun.caterpillar.model;

import org.springframework.mail.SimpleMailMessage;

import org.springframework.mail.javamail.JavaMailSenderImpl;

public class SimpleMail {

private String smtpHost;

private String from;

public void sendPasswdMail(String email,

String username, String passwd) {

JavaMailSenderImpl senderImpl = new JavaMailSenderImpl();

senderImpl.setHost(getSmtpHost());

SimpleMailMessage mailMessage = new SimpleMailMessage();

mailMessage.setTo(email);

mailMessage.setFrom(getFrom());

Page 15: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��1�

mailMessage.setSubject("您的密碼");

mailMessage.setText(username + " 您好,您的密碼是 " + passwd);

senderImpl.send(mailMessage);

}

public void setSmtpHost(String smtpHost) {

this.smtpHost = smtpHost;

}

public String getSmtpHost() {

return smtpHost;

}

public void setFrom(String from) {

this.from = from;

}

public String getFrom() {

return from;

}

} 其中有關於 SMTP伺服器與寄件人郵件位址,可以使用 Spring來進行依賴注入,而不用直接撰寫在程式之中,如此在更換這些設定時就很方便。

Page 16: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��16

10.3 View設計 在 Spring線上書籤中,將使用 JSP作為網頁基礎,使用 Tag Files來設計可重複使用的網頁元件,並運用 Spring綁定標籤與 JSTL來進行頁面邏輯的呈現。

10.3.1 Tag Files 網頁中有許多共同的部份,像是網頁開頭(Header)、結尾(Footer)或是網站資訊、使用者功能選單等,這些可以使用 JSP 2.0 技術中的 Tag

Files 設計為 .tag 檔案,並在必要的時候包括在網頁之中,如此撰寫網頁時就不用重複撰寫相同的內容。 網頁開頭的 Tag File如下撰寫,包括了基本的樣式、網站名稱與 Logo的設置:

SpringBookmark header.tag

<%@tag description="每個網頁的 Header" pageEncoding="BIG5"%>

<html>

<head>

<title>Spring 線上書籤</title>

<style>

body {font-family: Arial, Helvetica, sans-serif;

font-size: 13px}

li, td {Arial, Helvetica, sans-serif;

font-size: 13px}

hr {color: #3333cc; width: 300;

text-align: left}

a {color: #000000}

</style>

</head>

<body>

<img src='images/caterpillar.jpg'

alt='Spring 線上書籤 Logo' border='0' align='left'

valign='bottom'/>

Page 17: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��17

<h1>&nbsp;Spring 線上書籤</h1>

<hr style="width: 100%; height: 2px;">

<hr style="width: 100%; height: 2px;"> 網站中有些部份要出現網址的相關訊息,這可以撰寫一個 site_info.tag檔案:

SpringBookmark site_info.tag

<%@tag description="網站訊息" pageEncoding="BIG5"%>

<ul>

&nbsp;&nbsp;<li>線上儲存您的書籤

&nbsp;&nbsp;<li>分享您我的書籤

&nbsp;&nbsp;<li>快來秀出最酷的鏈結

</ul> 在使用者登入網頁之後,必須出現功能選單供使用者進行功能選擇,每一個畫面中都要出現,因此也可以將功能選單設計為可重複使用的 Tag

File,例如:

SpringBookmark usermenu.tag

<%@tag description="使用者功能表單" pageEncoding="BIG5"%>

<hr style="width: 100%; height: 2px;">

<a href='member.do'>會員首頁</a> &nbsp;|&nbsp;

<a href='member.do?action=addUrl'>加入書籤</a> &nbsp;|&nbsp;

<a href='member.do?action=changePasswd'> 改變密碼</a> &nbsp;|&nbsp;

<a href='member.do?action=logout'>登出</a>

<hr style="width: 100%; height: 2px;"> 最後別忘了,由於每個網頁的結尾都是差不多的,因此可以設計一個footer.tag檔案:

Page 18: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��18

SpringBookmark footer.tag

<%@tag description="每個網頁的 Footer" pageEncoding="BIG5"%>

</body>

</html> 設計完以上可重複使用的 Tag Files後,以後在撰寫網頁時,如果在開頭、結尾或是網址訊息等需要更改時,可直接更改 Tag Files,則使用到這些 Tag Files的網頁,在下一次請求時也就會自動更新內容。

10.3.2 註冊網頁 當使用者第一次來到網站時,必須先註冊一個帳號以成為合法的使用者,所以必須提供使用者一個註冊網頁,這邊可以使用 Spring的綁定標籤(參考 8.1.2),將接受使用者輸入的 Command物件綁定至網頁上的欄位,以提供相對應於欄位的訊息,註冊網頁的設計如下所示:

SpringBookmark register.jsp

<%@ page language="java" contentType="text/html; charset=BIG5"

pageEncoding="BIG5"%>

<%@taglib prefix="caterpillar" tagdir="/WEB-INF/tags" %>

<%@taglib prefix="spring"

uri="http://www.springframework.org/tags"%>

<caterpillar:header/>

<spring:bind path="command.*">

<font color="red">

<b>${status.errorMessage}</b>

</font><br>

</spring:bind>

<form method='post' action='register.do'>

<table bgcolor=#cccccc>

<tr>

<td>郵件位址:</td>

<td>

Page 19: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��1�

<spring:bind path='command.email'>

<input type='text' name='${status.expression}'

value='${status.value}' size='30'

maxlength='100'>

</spring:bind>

</td>

</tr>

<tr>

<td>名稱(最大 16字元):</td>

<td valign='top'>

<spring:bind path='command.username'>

<input type='text' name='${status.expression}'

value='${status.value}'

size='16' maxlength='16'>

</spring:bind>

</td>

</tr>

<tr>

<td>密碼(6到 16字元):</td>

<td valign='top'>

<spring:bind path='command.passwd'>

<input type='password' name='${status.expression}'

size='16' maxlength='16'>

</spring:bind>

</td>

</tr>

<tr>

<td>確認密碼:</td>

<td>

<spring:bind path='command.passwd2'>

<input type='password' name='${status.expression}'

size='16' maxlength='16'>

</spring:bind>

</td>

</tr>

<tr>

<td colspan='2' align='center'>

<input type='submit' value='註冊'></td></tr>

</table></form>

<caterpillar:footer/>

Page 20: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��2�

執行網頁後,所呈現的畫面如下所示:

圖 10.2 註冊網頁 註冊成功的話,會出現一個註冊成功的網頁,並直接將使用者登入,使用者將可以直接發現到一個連接到會員網頁的鏈結,註冊成功的網頁如下所示:

SpringBookmark register_success.jsp

<%@ page language="java" contentType="text/html; charset=BIG5"

pageEncoding="BIG5"%>

<%@taglib prefix="caterpillar" tagdir="/WEB-INF/tags" %>

<caterpillar:header/> 您的註冊已經成功,前往會員網頁!

<br><a href='member.do'>會員網頁</a><br>

<caterpillar:footer/>

Page 21: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��21

執行這個 JSP網頁後的畫面如下所示:

圖 10.3 註冊成功網頁

10.3.3 登入網頁 如果使用者已經註冊了,當連接到應用程式首頁時,可以顯示一個登入網頁,提供使用者輸入名稱與密碼進行登入,網頁的撰寫如下:

SpringBookmark login.jsp

<%@ page language="java" contentType="text/html; charset=BIG5"

pageEncoding="BIG5"%>

<%@taglib prefix="caterpillar" tagdir="/WEB-INF/tags" %>

<%@taglib prefix="spring"

uri="http://www.springframework.org/tags"%>

<caterpillar:header/>

<caterpillar:site_info/>

<a href='register.do'>還不是會員?</a><p>

<form method='POST' action='login.do'>

<spring:bind path="command.*">

<font color="red">

<b>${status.errorMessage}</b>

</font><br>

</spring:bind>

Page 22: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��22

<table bgcolor='#cccccc'>

<tr>

<td colspan='2'>會員登入</td>

<tr>

<td>名稱:</td>

<td>

<spring:bind path='command.username'>

<input type='text' name='${status.expression}'

value='${status.value}'>

</spring:bind>

</td>

</tr>

<tr>

<td>密碼:</td>

<td>

<spring:bind path='command.passwd'>

<input type='password'

name='${status.expression}'>

</spring:bind>

</td>

</tr>

<tr>

<td colspan='2' align='center'>

<input type='submit' value='登入'></td></tr>

<tr>

<td colspan='2'><a href='forgot.do'>忘記密碼?</a></td>

</tr>

</table></form>

<caterpillar:footer/> 網頁執行之後的畫面如下所示:

Page 23: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��23

圖 10.4 登入網頁 登入成功的話,會出現一個登入成功的網頁,使用者可以直接連接到會員網頁,登入成功的網頁如下所示:

SpringBookmark login_success.jsp

<%@ page language="java" contentType="text/html; charset=BIG5"

pageEncoding="BIG5"%>

<%@taglib prefix="caterpillar" tagdir="/WEB-INF/tags" %>

<caterpillar:header/> 登入成功,前往會員網頁!

<br><a href='member.do'>會員網頁</a><br>

<caterpillar:footer/>

Page 24: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��24

一個登入成功的畫面如下所示:

圖 10.5 登入成功網頁

10.3.4 會員網頁 當使用者登入並連結至會員網頁之後,預設會顯示使用者目前所擁有的書籤,在書籤網頁上可以讓使用者選擇是否刪除某些書籤,並提供有其它功能的選單,讓使用者進行不同的功能操作,會員網頁的設計如下所示:

SpringBookmark member.jsp

<%@ page language="java" contentType="text/html; charset=BIG5"

pageEncoding="BIG5"%>

<%@taglib prefix="caterpillar" tagdir="/WEB-INF/tags" %>

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

<caterpillar:header/>

<br> ${valid_user} 您好:<br><br>

<form name='bm_table' action='member.do' method='post'>

<table width='300' cellpadding='2' cellspacing='0'>

<tr bgcolor='#cccccc'><td><strong>書籤</strong></td>

<td><strong>刪除?</strong></td></tr>

<c:forEach var="url" items="${urls}" >

<tr bgcolor='#ffffff'>

<td><a href=<c:out value="${url}"/>>

<c:out value="${url}"/>

</a></td>

Page 25: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��2�

<td><input type='checkbox' name='del_me'

value=<c:out value="${url}"/>></td>

</tr>

</c:forEach>

<tr bgcolor='#ffffff'>

<td></td>

<td>

<input type='hidden' name='action'

value='deleteUrl'>

<input type='submit' value='刪除'>

</td>

</tr>

</table>

</form>

<caterpillar:usermenu/>

<caterpillar:footer/> 由於事先無法決定使用者所擁有的書籤數量,為了安排頁面邏輯,頁面中使用了 JSTL的 <forEach> 標籤以及 <out> 標籤來重複輸出書籤鏈結的 HTML,如此在網頁中就不用撰寫 Scriplet,來看一個有書籤時的參考畫面:

圖 10.6 會員網頁

Page 26: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��26

10.3.5 加入書籤網頁 當按下會員網頁下方的功能表中之「加入書籤」時,可以連結至加入書籤的網頁,使用者在這個網頁中輸入網站的 URL,以進行書籤的新增,加入書籤的網頁撰寫如下:

SpringBookmark addbm.jsp

<%@ page language="java" contentType="text/html; charset=BIG5"

pageEncoding="BIG5"%>

<%@taglib prefix="caterpillar" tagdir="/WEB-INF/tags" %>

<caterpillar:header/>

<form name='bm_table' action='member.do' method='post'>

<table width='300' cellpadding='2'

cellspacing='0' bgcolor='#cccccc'>

<tr><td>新書籤:</td>

<td><input type='text'

name='new_url' value='http://'

size='30' maxlength='255'>

</td>

</tr>

<tr><td colspan='2' align='center'>

<input type='hidden' name='action' value='addUrl'>

<input type='submit' value='新增書籤'></td></tr>

</table>

</form>

<caterpillar:usermenu/>

<caterpillar:footer/> 執行的畫面如下所示:

Page 27: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��27

圖 10.7 加入書籤網頁

10.3.6 改變、取回密碼網頁 使用者在登入之後,可以於按下「改變密碼」鏈結之後,直接進行密碼的更改,網頁撰寫如下:

SpringBookmark change_passwd.jsp

<%@ page language="java" contentType="text/html; charset=BIG5"

pageEncoding="BIG5"%>

<%@taglib prefix="caterpillar" tagdir="/WEB-INF/tags" %>

<caterpillar:header/>

<br>

<form action='member.do' method='post'>

<table width='250' cellpadding='2'

cellspacing='0' bgcolor='#cccccc'>

<tr><td>新密碼:</td>

<td>

<input type='password' name='new_passwd'

size='16' maxlength='16'>

<input type='hidden' name='action'

value='changePasswd'>

</td>

</tr>

<tr><td colspan='2' align='center'>

<input type='submit' value='改變密碼'> </td></tr>

Page 28: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��28

</table>

<br>

</form>

<caterpillar:usermenu/>

<caterpillar:footer/> 改變密碼的網頁呈現如下所示:

圖 10.8 改變密碼網頁 如果使用者因為忘記密碼無法登入,則可以在登入網頁的下方選擇「忘記密碼?」鏈結,輸入註冊時所使用的 Email位址,系統就可以發一封郵件給使用者告知密碼,該網頁的設計如下所示:

SpringBookmark forgot.jsp

<%@ page language="java" contentType="text/html; charset=BIG5"

pageEncoding="BIG5"%>

<%@taglib prefix="caterpillar" tagdir="/WEB-INF/tags" %>

<caterpillar:header/>

<br>

<form action='forgot.do' method='post'>

<table width='250' cellpadding='2'

cellspacing='0' bgcolor='#cccccc'>

Page 29: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��2�

<tr><td>輸入郵件地址:</td> <td><input type='text' name='email'

size='16' maxlength='100'></td>

</tr>

<tr><td colspan='2' align='center'>

<input type='submit' value="寄出密碼"> </td></tr>

</table>

<br>

<caterpillar:footer/> 網頁執行時的畫面如下所示:

圖 10.9 取回密碼網頁

10.3.7 首頁重新導向 在 Spring線上書籤中,所有的使用者請求都要先經過前端控制器,如果使用者直接使用 http://localhost:8080/SpringBookmark/這樣的網址時,會連接至伺服器預設的 Welcome 網頁,您應該提供一個 index.jsp 作為Welcome 網頁,當使用者連接至這個網頁時,將之重新導向至http://localhost:8080/SpringBookmark/login.do,以進行使用者登入,index.jsp的設計如下所示:

Page 30: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��3�

SpringBookmark index.jsp

<%@ page language="java" contentType="text/html; charset=BIG5"

pageEncoding="BIG5"%>

<jsp:forward page="login.do"/> 到這邊為止,所有的網頁設計完成,可以看到,網頁中沒有任何的 Java程式碼出現,有的只是網頁標籤,這是使用 Web MVC架構的好處,程式邏輯與畫面呈現邏輯不會混雜在一起。

Page 31: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��31

10.4 Controller設計 前一個小節中所設計的 JSP 網頁必須搭配相關的 Controller、Command或是資料物件,才可以呈現出所需的資料,Controller物件也是將 Model與 View結合在一起的主要關鍵,這個小節來看看,Spring線上書籤中 Controller的相關設計。

10.4.1 RegisterController 在使用者進行註冊的時候,可以使用一個 RegisterForm物件收集使用者的請求參數值,並可以運用它與 Spring綁定標籤合作,在相關的驗證失敗時於網頁上顯示錯誤訊息,RegisterForm的設計如下所示:

SpringBookmark RegisterForm.java

package onlyfun.caterpillar.web;

public class RegisterForm {

private String email;

private String username;

private String passwd;

private String passwd2;

public void setEmail(String email) {

this.email = email;

}

public void setUsername(String username) {

this.username = username;

}

public void setPasswd(String passwd) {

this.passwd = passwd;

}

public void setPasswd2(String passwd2) {

this.passwd2 = passwd2;

Page 32: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��32

}

public String getEmail() {

return email;

}

public String getUsername() {

return username;

}

public String getPasswd() {

return passwd;

}

public String getPasswd2() {

return passwd2;

}

} 使用者填寫註冊表單並送出之後,需要作一些驗證檢查動作,例如檢查使用者的郵件格式是否正確,密碼長度是否在 6 個字元至 16 個字元之間,兩次輸入的密碼是否相同等,這可以使用一個 RegisterValidator物件來完成相關的驗證檢查動作,這個物件實作了 Spring的 Validator介面(參考 7.3.1),撰寫方式如下所示:

SpringBookmark RegisterValidator.java

package onlyfun.caterpillar.web;

import org.springframework.validation.Errors;

import org.springframework.validation.Validator;

public class RegisterValidator implements Validator {

public boolean supports(Class clazz) {

return clazz.equals(RegisterForm.class);

}

public void validate(Object obj, Errors errors) {

RegisterForm form = (RegisterForm) obj;

Page 33: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��33

if(!validateEmail(form.getEmail())) {

errors.rejectValue("email",

"invalid_email", null, "郵件格式不正確");

}

if(form.getPasswd().length() < 6 ||

form.getPasswd().length() > 16) {

errors.rejectValue("passwd",

"less-or-over", null, "密碼長度必須是 6到 16字元");

}

if(!form.getPasswd().equals(form.getPasswd2())) {

errors.rejectValue(

"passwd", "not-equal", null, "兩次輸入的密碼不符");

}

}

private boolean validateEmail(String email) {

return email.matches("^[_a-z0-9-]+([.]" +

"[_a-z0-9-]+)*@[a-z0-9-]+([.][a-z0-9-]+)*$");

}

}

RegisterController 類別將繼承 Spring 的 SimpleFormController 類別(參考 7.2.7),這個 Validator物件可以直接使用 Spring的依賴注入來設定至 Controller,來看一下 RegisterController類別的撰寫:

SpringBookmark RegisterController.java

package onlyfun.caterpillar.web;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import onlyfun.caterpillar.model.IUserDAO;

import onlyfun.caterpillar.model.User;

import org.springframework.validation.BindException;

import org.springframework.web.servlet.ModelAndView;

import org.springframework.web.servlet.

mvc.SimpleFormController;

Page 34: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��34

public class RegisterController extends SimpleFormController {

private IUserDAO userDAO;

public RegisterController() {

setCommandClass(RegisterForm.class);

}

protected ModelAndView onSubmit(HttpServletRequest request,

HttpServletResponse response,

Object command,

BindException exception) throws Exception {

RegisterForm form = (RegisterForm) command;

User user = new User();

user.setEmail(form.getEmail());

user.setUsername(form.getUsername());

user.setPasswd(form.getPasswd());

this.getUserDAO().insert(user);

request.getSession().setAttribute(

"valid_user", form.getUsername());

return new ModelAndView(this.getSuccessView());

}

public void setUserDAO(IUserDAO userDAO) {

this.userDAO = userDAO;

}

public IUserDAO getUserDAO() {

return userDAO;

}

} 在 RegisterController 中,將從 RegisterForm 中擷取相關資訊,並設定至一個 User的實例中,接下來取得 IUserDAO物件,以將 User物件中的訊息儲存至資料庫的 user表格,注意到 RegisterForm是屬於 Web層所設計的 API,雖然它當中就帶有使用者的註冊訊息,但不建議直接將 Web

Page 35: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��3�

層所設計的 API侵入至商務層之中,而改使用一個與 Web層無關的 User物件來封裝使用者註冊訊息。

IUserDAO 的實例將使用 Spring 的依賴注入功能設定,註冊完成之後,在 Session物件的屬性中設定 "valid_user",使用者是否登入即是根據這個屬性來進行判斷。

10.4.2 LoginController 在使用者進行登入的時候,可以使用一個 LoginForm物件來收集使用者的請求參數值,並可以運用它與 Spring綁定標籤合作,在登入失敗時於網頁上顯示錯誤訊息,LoginForm的設計如下所示:

SpringBookmark LoginForm.java

package onlyfun.caterpillar.web;

public class LoginForm {

private String username;

private String passwd;

public void setUsername(String username) {

this.username = username;

}

public void setPasswd(String passwd) {

this.passwd = passwd;

}

public String getUsername() {

return username;

}

public String getPasswd() {

return passwd;

}

}

Page 36: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��36

接著設計 LoginController類別,在處理登入時,會檢查使用者名稱與密碼是否符合,如果符合的話,在 Session 物件的屬性中設定 "valid_

user",使用者是否登入即是根據這個屬性來進行判斷,如果不符合則設定相關錯誤訊息並送回至登入頁面,LoginController類別的撰寫如下所示:

SpringBookmark LoginController.java

package onlyfun.caterpillar.web;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import onlyfun.caterpillar.model.IUserDAO;

import onlyfun.caterpillar.model.User;

import org.springframework.validation.BindException;

import org.springframework.web.servlet.ModelAndView;

import org.springframework.web.servlet.

mvc.SimpleFormController;

public class LoginController extends SimpleFormController {

private IUserDAO userDAO;

public LoginController() {

this.setCommandClass(LoginForm.class);

}

protected ModelAndView onSubmit(HttpServletRequest request,

HttpServletResponse response,

Object command,

BindException exception)

throws Exception {

LoginForm form = (LoginForm) command;

User user = userDAO.findByName(form.getUsername());

if(user == null) {

exception.rejectValue("username",

"no_such_user", "查無此人");

return new ModelAndView(

this.getFormView(), exception.getModel());

}

Page 37: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��37

else if(user != null &&

!user.getPasswd().equals(form.getPasswd())) {

exception.rejectValue("passwd",

"wrong_passwd", "密碼錯誤");

return new ModelAndView(

this.getFormView(), exception.getModel());

}

else {

request.getSession().setAttribute(

"valid_user", user.getUsername());

return new ModelAndView(this.getSuccessView());

}

}

public void setUserDAO(IUserDAO userDAO) {

this.userDAO = userDAO;

}

public IUserDAO getUserDAO() {

return userDAO;

}

}

10.4.3 MemberController 會員登入之後,接下來可以進行個人書籤的顯示、加入或刪除書籤、更改密碼、登出等動作,這些動作都是屬於會員才會擁有的功能,因此為了集合管理這些操作,可以繼承 Spring的 MultiActionController類別來撰寫這些操作的處理(參考 7.2.2),而不用為每個操作撰寫一個 Controller類別,來看一下 MemberController的撰寫:

SpringBookmark MemberController.java

package onlyfun.caterpillar.web;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

Page 38: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��38

import onlyfun.caterpillar.model.IBookmarkDAO;

import onlyfun.caterpillar.model.IUserDAO;

import onlyfun.caterpillar.model.User;

import org.springframework.web.servlet.ModelAndView;

import org.springframework.web.servlet.mvc.

multiaction.MultiActionController;

import org.springframework.web.servlet.view.RedirectView;

public class MemberController extends MultiActionController {

private IBookmarkDAO bookmarkDAO;

private IUserDAO userDAO;

private String memberPage;

private String addBmPage;

private String passwdPage;

private String redirectPage;

// 顯示個人書籤

public ModelAndView displayUrl(HttpServletRequest req,

HttpServletResponse res) {

String username =

(String) req.getSession().getAttribute("valid_user");

if(username != null) {

// 根據使用者名稱查找書籤

List urls =

getBookmarkDAO().findUserUrl(username);

return new ModelAndView(

this.getMemberPage(), "urls", urls);

}

else {

return new ModelAndView(

new RedirectView(getRedirectPage()));

}

}

// 加入新的書籤

public ModelAndView addUrl(HttpServletRequest req,

HttpServletResponse res) {

String username =

(String) req.getSession().getAttribute("valid_user");

if(username != null) {

if(req.getParameter("new_url") != null) {

Page 39: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��3�

String url = (String) req.getParameter("new_url");

// 加入新的書籤網址

getBookmarkDAO().addUserUrl(username, url);

return displayUrl(req, res);

}

else {

return new ModelAndView(this.getAddBmPage());

}

}

else {

return new ModelAndView(

new RedirectView(getRedirectPage()));

}

}

// 刪除所選擇的書籤

public ModelAndView deleteUrl(HttpServletRequest req,

HttpServletResponse res) {

String username =

(String) req.getSession().getAttribute("valid_user");

if(username != null) {

if(req.getParameterValues("del_me") != null) {

String[] deleted_urls =

(String[]) req.getParameterValues("del_me");

// 刪除所指定的書籤

getBookmarkDAO().deleteUserUrls(

username, deleted_urls);

return displayUrl(req, res);

}

else {

return new ModelAndView(this.getAddBmPage());

}

}

else {

return new ModelAndView(

new RedirectView(getRedirectPage()));

}

}

// 改變密碼

public ModelAndView changePasswd(HttpServletRequest req,

HttpServletResponse res) {

Page 40: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��4�

String username =

(String) req.getSession().getAttribute("valid_user");

if(username != null) {

if(req.getParameter("new_passwd") != null) {

String passwd = req.getParameter("new_passwd");

User user = getUserDAO().findByName(username);

user.setPasswd(passwd);

getUserDAO().update(user);

return displayUrl(req, res);

}

else {

return new ModelAndView(this.getPasswdPage());

}

}

else {

return new ModelAndView(

new RedirectView(getRedirectPage()));

}

}

// 登出

public ModelAndView logout(HttpServletRequest req,

HttpServletResponse res) {

req.getSession().invalidate();

return new ModelAndView(

new RedirectView(getRedirectPage()));

}

public void setBookmarkDAO(IBookmarkDAO bookmarkDAO) {

this.bookmarkDAO = bookmarkDAO;

}

public IBookmarkDAO getBookmarkDAO() {

return bookmarkDAO;

}

public void setUserDAO(IUserDAO userDAO) {

this.userDAO = userDAO;

}

Page 41: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��41

public IUserDAO getUserDAO() {

return userDAO;

}

public String getMemberPage() {

return memberPage;

}

public void setMemberPage(String memberPage) {

this.memberPage = memberPage;

}

public String getAddBmPage() {

return addBmPage;

}

public void setAddBmPage(String addBmPage) {

this.addBmPage = addBmPage;

}

public String getPasswdPage() {

return passwdPage;

}

public void setPasswdPage(String passwdPage) {

this.passwdPage = passwdPage;

}

public String getRedirectPage() {

return redirectPage;

}

public void setRedirectPage(String redirectPage) {

this.redirectPage = redirectPage;

}

} 進行相關操作時,需要 IUserDAO及 IBookmarkDAO的實例,這可以使用 Spring的依賴注入來進行設定。

Page 42: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��42

10.4.4 ForgotController 當使用者忘記密碼而無法登入時,可以輸入註冊時所使用的郵件位址,系統會發一封信至指定的信箱,以上這些動作是在 ForgotController類別中定義的,來看一下它是如何撰寫的:

SpringBookmark ForgotController.java

package onlyfun.caterpillar.web;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import onlyfun.caterpillar.model.IUserDAO;

import onlyfun.caterpillar.model.SimpleMail;

import onlyfun.caterpillar.model.User;

import org.springframework.web.servlet.ModelAndView;

import org.springframework.web.servlet.

mvc.AbstractController;

public class ForgotController extends AbstractController {

private IUserDAO userDAO;

private SimpleMail simpleMail;

private String loginPage;

private String forgotPage;

public ModelAndView handleRequestInternal(

HttpServletRequest request,

HttpServletResponse response) throws Exception {

String email = request.getParameter("email");

if(email != null && !"".equals(email)) {

// 根據郵件位址查詢使用者的資料

User user = getUserDAO().findByEmail(email);

// 取得 SimpleMail實例並設定相關資料以發送郵件

getSimpleMail().sendPasswdMail(

user.getEmail(),

user.getUsername(),

user.getPasswd());

return new ModelAndView(this.getLoginPage());

}

else {

Page 43: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��43

return new ModelAndView(this.getForgotPage());

}

}

public void setUserDAO(IUserDAO userDAO) {

this.userDAO = userDAO;

}

public IUserDAO getUserDAO() {

return userDAO;

}

public void setSimpleMail(SimpleMail simpleMail) {

this.simpleMail = simpleMail;

}

public SimpleMail getSimpleMail() {

return simpleMail;

}

public void setLoginPage(String loginPage) {

this.loginPage = loginPage;

}

public String getLoginPage() {

return loginPage;

}

public void setForgotPage(String forgotPage) {

this.forgotPage = forgotPage;

}

public String getForgotPage() {

return forgotPage;

}

} 同樣的,相關的依賴物件也是使用 Spring的依賴注入來進行設定。

Page 44: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��44

10.5 組態設定 Spring 線上書籤所需要的頁面與類別等元件已撰寫完成,現在要將這一切串接在一起,以讓程式中的各個元件彼此可以合作,方法就是撰寫一些 XML檔案進行組態設定,讓 Spring可以使用其 Web MVC框架與容器功能,將整個程式運行起來。

10.5.1 設定 web.xml 在 web.xml中要設定 Spring的 DispatcherServlet(參考 7.1.2),並告知 Spring的 XML設定檔之名稱與所在位置,來看一下 web.xml中是如何撰寫的:

SpringBookmark web.xml

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

<web-app 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"

version="2.4">

<session-config>

<session-timeout>

30

</session-timeout>

</session-config>

<servlet>

<servlet-name>dispatcherServlet</servlet-name>

<servlet-class>

org.springframework.web.servlet.DispatcherServlet

</servlet-class>

<init-param>

<param-name>contextConfigLocation</param-name>

<param-value>/WEB-INF/web-config.xml,

Page 45: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��4�

→ /WEB-INF/model-config.xml</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>dispatcherServlet</servlet-name>

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

</servlet-mapping>

</web-app> 為了避免 Spring 的相關設定檔案內容過長,因此將 Web 層的Controller設定、View設定等在 web-config.xml中進行設定,而將相關的Model物件設定於 model-config.xml之中。

10.5.2 設定 web-config.xml 在 web-config.xml 中主要是設定 HandlerMapping、ViewResolver、Controller、View 等內容(請參考 7.1 節相關的內容),直接來看看如何撰寫:

SpringBookmark web-config.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">

<bean id="urlMapping"

class="org.springframework.web.servlet.

→ handler.SimpleUrlHandlerMapping">

<property name="mappings">

<props>

<prop key="/login.do">loginController</prop>

<prop key="/register.do">registerController</prop>

<prop key="/member.do">memberController</prop>

Page 46: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��46

<prop key="/forgot.do">forgotController</prop>

</props>

</property>

</bean>

<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/jsp/"/>

<property name="suffix" value=".jsp"/>

</bean>

<bean id="loginController"

class="onlyfun.caterpillar.web.LoginController">

<property name="userDAO" ref="userDAO"/>

<property name="successView" value="login_success"/>

<property name="formView" value="login"/>

</bean>

<bean id="registerValidator"

class="onlyfun.caterpillar.web.RegisterValidator"/>

<bean id="registerController"

class="onlyfun.caterpillar.web.RegisterController">

<property name="validator" ref="registerValidator"/>

<property name="userDAO" ref="userDAO"/>

<property name="successView" value="register_success"/>

<property name="formView" value="register"/>

</bean>

<bean id="paraMethodResolver"

class="org.springframework.web.servlet.mvc.

→ multiaction.ParameterMethodNameResolver">

<property name="paramName" value="action"/>

<property name="defaultMethodName" value="displayUrl"/>

</bean>

<bean id="memberController"

class="onlyfun.caterpillar.web.MemberController">

<property name="methodNameResolver"

ref="paraMethodResolver"/>

Page 47: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��47

<property name="bookmarkDAO" ref="bookmarkDAO"/>

<property name="userDAO" ref="userDAO"/>

<property name="memberPage" value="member"/>

<property name="addBmPage" value="addbm"/>

<property name="passwdPage" value="change_passwd"/>

<property name="redirectPage"

value="/SpringBookmark/login.do"/>

</bean>

<bean id="forgotController"

class="onlyfun.caterpillar.web.ForgotController">

<property name="userDAO" ref="userDAO"/>

<property name="simpleMail" ref="simpleMail"/>

<property name="loginPage" value="login"/>

<property name="forgotPage" value="forgot"/>

</bean>

</beans>

10.5.3 設定 model-config.xml 在 model-config.xml中,則是撰寫資料庫的基本訊息、Hibernate相關的配置、以及 UserDAO、BookmarkDAO的定義(參考 6.2節的內容),另外有關 SimpleMail的定義,也在這個檔案中撰寫:

SpringBookmark model-config.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">

<!-- 要設定您的資料庫相關訊息 -->

<bean id="dataSource"

class="org.springframework.jdbc.

→ datasource.DriverManagerDataSource">

<property name="driverClassName"

value="com.mysql.jdbc.Driver"/>

<property name="url"

value="jdbc:mysql://localhost:3306/bookmarks"/>

Page 48: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1��48

<property name="username" value="your_db_username"/>

<property name="password" value="your_db_password"/>

</bean>

<bean id="sessionFactory"

class="org.springframework.orm.

→ hibernate3.LocalSessionFactoryBean"

destroy-method="destroy">

<property name="dataSource" ref="dataSource"/>

<property name="mappingResources">

<list>

<value>onlyfun/caterpillar/model/User.hbm.xml</value>

<value>onlyfun/caterpillar/model/Bookmark.hbm.xml</value>

</list>

</property>

<property name="hibernateProperties">

<props>

<prop key="hibernate.dialect">

org.hibernate.dialect.MySQLDialect

</prop>

</props>

</property>

</bean>

<bean id="hibernateTemplate"

class="org.springframework.orm.

→ hibernate3.HibernateTemplate">

<property name="sessionFactory" ref="sessionFactory"/>

</bean>

<bean id="userDAO"

class="onlyfun.caterpillar.model.UserDAO">

<property name="hibernateTemplate" ref="hibernateTemplate"/>

</bean>

<bean id="bookmarkDAO"

class="onlyfun.caterpillar.model.BookmarkDAO">

<property name="hibernateTemplate" ref="hibernateTemplate"/>

</bean>

<!-- 要設定您的 Smtp Server 與寄件人 -->

<bean id="simpleMail"

class="onlyfun.caterpillar.model.SimpleMail">

Page 49: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Chapter 10 專案:Spring 線上書籤

1��4�

<property name="smtpHost" value="your_smtp_server"/>

<property name="from" value="your_admin_address"/>

</bean>

</beans> 到這邊為止,Spring 線上書籤所必須的檔案都已撰寫完成,最後別忘了要設定相關的 .jar檔案,然後就可以開始運行您的程式了,可以在光碟中找到 SpringBookmark 專案,並修改當中的一些個人化配置,例如資料庫使用者名稱、密碼等,以及 Mail的相關設定,然後使用 WTP運行程式,就可以看看 Spring線上書籤運行時的功能。

Page 50: Spring 2.0 技術手冊第十章 - 專案:線上書籤

Spring 2.0 技術手冊(林信良 – http://openhome.cc)

1����

10.6 接下來的主題 本書到這邊要告一段落了,最後要補充一點的是,在 Spring下載檔案中有一個 samples目錄,當中有一些 Spring的範例程式可以參考,建議您可以看一下 jpetstore目錄下的範例程式,這也是一個觀摩如何使用 Spring相當好的範例。

圖 10.10 試著用 Spring 寫個程式吧