效果圖
在此用我們前面所了解的Struts來制作一個簡單的流言板。
這么樣,通過幾副圖,我想大家對這個留言板的大至流程已經有個了解了吧,它還是我們前面那個登錄驗證的例子,只不過,界面我稍微美化了一下,沒想吧,我們竟然用了一個登錄驗證的例子,進行進階,學習完struts這個系列的教程,是的,就這么簡單,希望大家在學習別的語言時,也這么去做,你會發現你進步的很快,不妨可以去試試,希望大家關注我的其他系列的教程哦。
程序流程設計及實現
一、 數據庫
這個示例主要是對兩個表的管理。
1) 用戶表
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(100) default NULL,
`password` varchar(100) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2) 留言表
CREATE TABLE `guestbook` (
`id` int(11) NOT NULL auto_increment,
`user_id` int(11) default NULL,
`message` text,
`date` datetime default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
二、 模型層
因為這是個簡單的示例,模型我們就用JDBC把,在日后的進階中你可以改成Hibernate的。接下來,我們分別建立兩個bean:
1) userBean.java
public class UserBean
implements Serializable {
private int id;
private String username;
private String password;
public UserBean() {
}
setXXX()和getXXX()
}
2) GuestbookBean.java
public class GuestbookBean
implements Serializable {
private int id;
private String username;
private String message;
private String date;
private DataSource dataSource;
public GuestbookBean() {
}
setXXX()和getXXX();
}
三、 Controller(控制層)
一、 修改Action
LoginAction.java
LoginActionForm loginform = (LoginActionForm) actionForm;
HttpSession session = request.getSession();
String username = loginform.getUsername();
String userpass = loginform.getUserpass();
//獲取ServletContext對象
ServletContext ctx = servlet.getServletContext();
//獲取數據連接對象
DataSource ds = (DataSource) ctx.getAttribute("DataSource");
//因為邏輯處理我沒用DAO,交給Bean處理了,所以需要一個數據連接對象
UserBean userBean = new UserBean(ds);
String actionpath = "";
//我在userBean中加的isLogin方法,用于驗證用戶登錄是否成功,如果成功的化返回
返回true,否則返回false(表示登錄失敗,改用戶不存在)。
boolean flag = userBean.isLogin(username,userpass);
if (flag) {
//當用戶登錄成功,我們要顯示所有的留言,所以還得需要一個//GuestbookBean。這個bean也需要一個ds對象,因為它的getGuestbook方法//是返回所有的流言。
GuestbookBean gb = new GuestbookBean(ds);
//把userBean設置到session中,當用戶發表評論是顯示其用戶的名稱,以達 //到用戶與留言關聯起來
session.setAttribute("userBean", getUserBean(username,userpass));
//取得留言集合放到request中,馬上到頁面顯示出來。
request.setAttribute("guestBookList", gb.getGuestbook());
actionpath = "success";
} else {
actionpath = "error";
}
return actionMapping.findForward(actionpath);
}
二、 新建一個GuestbookOptAction.
有兩個方法,getAllGuestbook()和addGuestbook(),分別是獲取所有的留言、增加留言。
創建一個FormBean
public class GuestbookForm
extends ActionForm {
private String message;
setXXX()和getXXX();
}
創建GuestbookOptAction.java
public class GuestbookOptAction
extends DispatchAction {
public ActionForward getAllGuestbook(ActionMapping mapping,
ActionForm actionForm,
HttpServletRequest request,
HttpServletResponse response) {
ServletContext ctx = servlet.getServletContext();
DataSource ds = (DataSource) ctx.getAttribute("DataSource");
GuestbookBean gb = new GuestbookBean(ds);
request.setAttribute("guestBookList", gb.getGuestbook());
return mapping.findForward("goToGuestbookPage");
}
public ActionForward addGuestbook(ActionMapping mapping,
ActionForm actionForm,
HttpServletRequest request,
HttpServletResponse response) {
GuestbookForm gurestbookForm =(GuestbookForm) actionForm;
ServletContext ctx = servlet.getServletContext();
DataSource ds = (DataSource) ctx.getAttribute("DataSource");
GuestbookBean gb = new GuestbookBean(ds);
//取得用戶留言內容
gb.setMessage(gurestbookForm.getMessage());
//獲取session這個用戶的編號
int userId = Integer.parseInt(request.getParameter("userId"));
//添加一個留言,這里userId告訴程序,用戶與留言進行關聯
gb.addGuestbook(gb, userId);
//去得所有留言
return getAllGuestbook(mapping,actionForm,request,response);
}
四、 修改struts-config.xml
<action
path="/login"
name="loginActionForm"
scope="request"
type="org.zhoudq.webapp.action.LoginAction"
validate="true"
input="/login.jsp">
<forward name="success" path="/guestbook.jsp" />
<forward name="error" path="/login.jsp" />
</action>
<action
path="/getGuestBook"
name="guestbookForm"
parameter="method"
type="org.zhoudq.webapp.action.GuestbookOptAction">
<forward name="goToGuestbookPage" path="/guestbook.jsp"/>
</action>
五、 頁面(View)
Login.jsp、guestbook.jsp
流程也就就用戶登錄成功,在guestbook.jsp顯示所有的流言列表,然后可以添加留言。
因為頁面設計后,代碼變多了,這里就不貼出來了。如果想索取程序,請與本人聯系,
Email:zhdqCN@gmail.com。
六、 運行測試
打開瀏覽器,鍵入:http://localhost:8080/Struts1_Login/
就可以操作了,就能看到上面的畫面了,一個登錄示例帶著我們學會了如何去用Struts,不過Struts遠遠不只是這寫,希望大家繼續學習,有什么問題日后大家可以互相交流,哈。
在使用Struts框架時,每個請求都由Action去處理,并且還要在struts-config.xml中加以設定,這樣以來做小項目還行,在大型網站的開發中,有很多小組負責不同的模塊,如果每一個小組要對一個struts-config.xml進行設定,將會導致struts-config.xml的版本控制問題。
您可以為每個小組分配不同的struts-config.xml設定文件,方法是在ActionServlet參數的config參數后面加上后綴,如果是config/admin,那么相應的配置文件的名字就是:struts-config-admin,他們的后綴名字必須對應,這樣才能映射上。
例如我們可以把后臺處理分配一個小組,設定具體代碼如下所示:web.xml
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/conf/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>config/admin</param-name>
<param-value>/WEB-INF/conf/struts-confg-admin.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>3</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
config/admin:指定了admin模塊的所使用的配置文件是struts-config-admin.xml,現在負責后臺模塊的開發人員只要管理自己的開發文檔設定就行了,就像前面所說的一樣,當ActionServlet收到請求時,它是根據模塊你所指定的后綴,進行處理是哪個模塊的請求。
例如:
http://localhost:8080/strutsmodel/admin/admin.do
這個URL,表示請求由strutsmodel工程的admin環境的admin.do來處理這個請求。這樣以來前臺和后臺就分明了,各自開發各自的,各自管理自己的配置文件,達到松耦合的目的。
當ActionServlet請求接收請求,它判斷URL中相對與context的前綴,例如上例中的admin,于是就知道應該使用admin模塊。下面是struts-config-admin.xml:
……
<action
path="/admin"
type="org.zhoudq.webapp.action.AdminAction" >
<forward name="admin" path="/admin.jsp" />
</action>
……
這樣以來所有的path設定將自動被加上login前綴,例如必須使用以下的路徑才可以正確的請求到AdminAction:
http://localhost:8080/strutsmodel/admin/admin.do
在模塊中的Action在查找forward時,都是以所在模塊,查找對應的struts-confg-XXX.xml的,例如上面的AdminAction在查找forward時,則會查找struts-config-admin.xml中的forward元素,也就是說,模塊中的forward對象的查找都是相對于模塊的路徑的,而不是相對與環境上下文。
那么我們模塊分配工作幾已經搞定了,各個小組可以分別開工了,但是問題來了,那么如何從當前的模塊換到另一個模塊呢?
當您的項目分作很多個模塊時,在使用者點某個鏈接時,您有兩個方法可以在模塊之間切換。
一、方法一
是使用相對與環境上下文的路徑進行forward轉發,您可以在當前的struts-config-XX.xml如下設定,例如是:struts-config-admin.xml中加入:
<global-forwards>
<forward
name="switchModuleToFront"
contextRelative="true"
path="/front/login.do"
redirect="true"/>
</global-forwards>
這個是全局可以找到的forward中設定的,下面是在action元素中設定如何轉發模塊,代碼如下:
……
<action
path="/admin"
type="org.zhoudq.webapp.action.AdminAction" >
<forward
name="admin"
contextRelative="true"
path="/front/login.do"
redirect="true"/>
</action>
……
上面這種配置就是通過forward元素轉換到相應的模塊,下面我們看另一種方法吧。
二、方法二
這種方法是我們通過配置Struts的一個特定的類SwitchAction,就能實現上面的要求了。并且需要兩個參數:
1. prefix:用來指定模塊的后綴名稱
2. page:用來指定你的資源路徑。
例如:
……
<action-mappings>
<action
path="/switch"
type="org.apache.struts.actions.SwitchAction"/>
</action-mappings>
……
例如:
http://localhost:8080/strutsmodel/switch.do?prefix=/admin&page=/admin.do
這個是訪問我們后臺模塊的admin.do資源。模塊化決絕了我們開發中的不少問題吧,希望能幫助您解決一些問題,嘿嘿,加油吧……
一、Struts的ActionForm的表單驗證
ActionForm類用于在視圖層和控制層之間傳遞HTML表單數據。控制層可以從ActionForm Bean中讀取用戶輸入的表單數據,也可以把來自模型層的數據存放到ActionForm Bean中,然后把數據返回給視圖。即ActionForm Bean從HTML表單中獲取用戶輸入的數據并將傳遞給Action類,也可以把從業務層返回的數據用來填充ActionForm Bean,然后JSP頁面用它來為HTML表單提供各種輸出字段的數據。此外,ActionForm Bean還具有表單驗證功能,可以過路不合法的數據。
ActionForm Bean有兩種存在范圍:request和session。如果ActionForm Bean存在于request范圍,它僅在當前的請求/響應生命周期中有效。如果ActionForm Bean存在于session范圍,同一個ActionForm Bean實例在整個HTTP會話中都有效。
在Struts框架中,使用ActionForm Bean來實現應用程序系統的非持久性數據存儲和維護功能,它采用了自動填充屬性和調用的機制。所以必須繼承ActionForm類,并且包涵用戶表單輸入的屬性,以及相應的get方法和set方法。另外,還可以根據需要重寫父類的reset()和validate()方法,實現屬性的重置和表單數據驗證功能。
Ø validate()方法
這個方法主要負責檢查數據的格式和語法,而不負責檢查數據是否符合業務邏輯。
ActionForm基類中的validate()方法在默認情況下將返回null。如果創建了ActionForm的子類,那么應該在子類覆蓋validate()方法。
Ø reset()方法
這個方法用于恢復ActionForm Bean 的屬性的默認值。例如:把字符串屬性設為null或某個初始值。
1、 修改前面我們寫的LoginActionForm,如果你不清楚的話,請您先看前幾個實例,具體代碼如下:
public ActionErrors validate(ActionMapping actionMapping,
HttpServletRequest httpServletRequest) {
ActionErrors errors = new ActionErrors();
if (username == null|| username.equals("")) {
errors.add(ActionErrors.GLOBAL_MESSAGE,
new ActionError("loginform.error.username"));
}
if (userpass == null||userpass.equals("")) {
errors.add(ActionErrors.GLOBAL_MESSAGE,
new ActionError("loginform.error.password"));
}
return errors;
}
這個方法返回ActionErrors對象,如果返回的ActionErrors對象為null,或者不包含任何ActionMessage對象,就表示沒有錯誤,數據驗證通過。如果ActionErrors中包含ActionMessage對象,就表示發生了驗證錯誤,此時就回把請求轉發到你struts.xml里面<action>元素input屬性指定的web資源。
new ActionError("loginform.error.username");取得資源文件里面的鍵值,用于頁面的輸出。
2、 打開applicationResource.properties,加入如下信息:
loginform.error.username=please enter your username
loginform.error.password=please enter your password
因為我們前面做了國際化,所以打開applicationResource_zh_CN.properties文件,添加如下:
loginform.error.username=請輸入用戶名
loginform.error.password=請輸入密碼
3、 修改struts-config.xml文件
<action
path="/login"
name="loginActionForm"
scope="request"
type="actions.LoginAction"
validate="true"
input="/login.jsp">
<forward name="success" path="/success.jsp" />
<forward name="error" path="/wrong.jsp" />
</action>
在<action>元素中,name和scope屬性分別指定ActionForm的名字和它的范圍,valudate屬性指定是否執行表單驗證,而input屬性表示驗證失敗,所要顯示用戶的內容。
4、 修改login.jsp,在<body>元素添加,目的是顯示錯誤信息,具體代碼片段如下:
<div>
<font color="red">
<html:messages id="error">
<li><bean:write name="error"/></li>
</html:messages>
</font>
</div>
<html:message/> :用于輸出消息。屬性介紹如下:
n name:指定ActionMessages對象存放在request或session范圍內的屬性key。標簽處理類將根據這一屬性key來檢索request或session范圍的ActionMessages對象。
n message屬性:指定消息的來源。如果為true,則從request或session范圍內檢索出屬性key為Globals.MESSAGE_KEY的ActionMessages對象,此時name屬性無效;如果為false,則根據name屬性來檢索ActionMessage對象,如果此時沒有設置name屬性,將采取默認值Globals.ERROR_KEY.message屬性的默認值為false。
n id屬性:用來命名從消息中檢索出來的每個ActionMessage對象,它和<bean:write>標簽的name屬性匹配。
<bean:write/>:表示顯示javaBean或其屬性的內容。
5、 運行
打開IE,鍵入如下地址:http://localhost:8080/Struts1_Login/login.jsp
不輸入任何東西,我們直接點幾擊“確定”,如下:
二、Struts的Validator驗證框架
Validator 目前是Jakarta Commons 項目的一部分,它也被包含在Struts主分發里面,可以直接使用Struts 中自帶的Validator 庫,也可以去網站上下載http://jakarta.apache.org/commons/。
Struts框架能夠通過ActionForm Bean的validate()方法對用戶輸入的表單數據進行驗證。但是這種驗證方式又有一定的局限性。必須由具體的代碼來實現驗證邏輯,如果驗證邏輯發生了改變,就需要重新編寫程序代碼。此外,如果系統中有多個ActionForm Bean,并且他們包含一些相同的驗證邏輯時,那么開發人員必須對每個ActionForm Bean進行重復開發呢?
Validator框架能夠克服在ActionForm Bean中進行數據驗證的局限性,它允許為Struts應用靈活的配置驗證規則,無需編程。
Validator框架主要依賴于兩個JAR文件:
Ø Jakarta-oro.jar
提供了一組處理文本的類,具有文本替換,過錄和分割等功能。
Ø commons-validator.jar
提供了一個簡單、可擴展的驗證框架,包含了通用的驗證方法和驗證規則。
主要的Struts驗證組件
組件 |
說明 |
驗證器 |
處理原生和其它通用類型。基本驗證器包括required,mask(匹配正則表達式),minLength,maxLength,range,nativetypes, date,email,和creditCard。也可以定義定制 (或者插件) 驗證器。 |
資源文件 |
提供(本地化的)標注和消息。默認與Struts 共享消息資源。 |
XML 配置文件 |
根據需要定義針對字段的表單集和驗證。驗證器可以在一個單獨的文件中定義。 |
JSP 標簽 |
對給定的表單或Action 路徑產生JavaScript 驗證器。 |
ValidatorForm |
根據FormBean 的名稱自動驗證屬性(在運行時通過ActionMapping 參數傳到validate 方法)。必須被擴展才能提供表單之上的期望屬性的驗證。 |
ValidatorActionForm |
基于action 路徑自動驗證屬性(在運行時通過ActionMapping參數傳到validate 方法)。必須被擴展才能提供表單之上的期望屬性的驗證。 |
有些字段可能必須要求有數據輸入。而郵政編碼總是具有已知的長度。其它公共字段類型包括數值、日期、身份證號碼等等。
驗證器本身具有一些基本的驗證器來處理這些公共需要,當然還有其它一些需要。如果你的驗證不能被基本驗證器或者正則表達式滿足,你可以開發你自己的驗證器并插入到包中。基本驗證器支持其自身附帶的基本插件。
安裝和配置
Validator框架采用兩個基于XML的配置文件來配置驗證規則。一個是validator-rules.xml,另一個是validation.xml,這兩個文件應該部署在對應于WEB應用程序的WEB-INF文件夾下,對應的兩個jar文件也添加到WEB-INF/lib目錄下。
1、 validation-rules.xml
在validation-rules.xml 文件中配置了一些全局性的驗證規則,使得你在應用程序中使用校驗而不用關注實現細節。這個配置文件是Validator 框架自帶的,可以用在所有Struts應用中。它默認配置了許多很常用的規則,一般來說,不用去更改它,除非需要擴展或修改這些默認的驗證規則。
建議:即使你需要擴展一些規則,也不要去修改validation-rules.xml,而是通過新的配置文件去定義你所擴展的校驗規則。
validator-rules.xml文件的根元素是form-validation,它包含一到多個global元素,global元素包含一到多個validator 元素。
每一個validator 元素定義了一個唯一的驗證規則。下面是validation-rules.xml 文件中的一個片斷, (mask)驗證規則:
<validator name="mask"
classname="org.apache.struts.validator.FieldChecks"
method="validateMask"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionMessages,
org.apache.commons.validator.Validator,
javax.servlet.http.HttpServletRequest"
depends=""
msg="errors.invalid"/>
1) name: 賦予驗證規則的一個唯一的名稱。
2) classname: 指的是具體實現驗證規則的類。
3) method: 指包含具體實現類的方法。
4) methodParams: 聲明method屬性所指定的方法參數,多個參數之間用逗號分隔。
5) depends: 指定在調用當前的嚴整規則之前必須先調用的其他驗證規則。多個則用逗號分隔。
6) msg: 指定來自于Resource Bundle中的消息key。當驗證失敗時,validator框架根據這個消息key到Resource Boundle中查找匹配的消息。
2、 validation.xml
Validator框架所需要的第二個配置文件是validation.xml,這個配置文件是具體應用(項目)所特定的,可以根據你的應用(項目)情況進行自定義配置。它描述了具體的ActionForm使用validation-rules.xml文件中的哪個驗證規則進行驗證。
一個自定義的驗證規則如下:
<form-validation>
<formset>
<form name="loginActionForm">
<field property="username" depends="required">
<arg key="label.username" />
</field>
<field property="userpass" depends="required">
<arg key="label.password" />
</field>
</form>
</formset>
</form-validation>
Validator.xml文件的根元素為<form-validation>元素,它包含兩個子元素:<global>和<formset>元素。
1) <global>元素可以定義<constant>子元素,它用來定義常量表達式。
2) <formset>元素包含兩個子元素:<contant>和<form>。
3) <form>元素用于為表單配置驗證規則,它的name屬性表示你驗證formBean,必須和struts-config.xml里面FormBean名字保持一致。<form>元素可以包含一個或多個<field>子元素。
4) <field>元素是針對表單中字段的驗證規則。Property屬性用于指定FormBean中需要驗證的字段的名稱,depends屬性用于指定字段的驗證規則,多個用逗號分隔。
5) <arg>元素表示出錯時的主體信息,key 是你屬性文件里面的key。
6) 主要是對前面<depends>元素包含的驗證規則的定義。
3、插入Validator
每一個Struts應用需要知道是否使用了Validator框架,可以通過PlugIn(插件)機制將Validator框架配置到Struts應用中。
下面的代碼演示了如何將Validator 作為一個插件加入到Struts 應用中,在Struts 應用的配置文件Struts-config.xml 中加入如下代碼片段:
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validator.xml"/>
</plug-in>
pathnames屬性的值用來指定Validator 框架所使用的配置文件,多個配置文件之間用逗號分隔。
當應用啟動的時候,Struts框架將調用ValidatorPlugIn的init()方法。Validator框架的配置文件將會加載到內存中供應用使用。在init()方法被調用之前,pathnames所指定的值將會傳遞給ValidatorPlugIn的實例,ValidatorPlugIn實例將會依據這個值去加載配置文件。
案例說明:根據前面的例子我們進行進階,要求用戶輸入用戶名、密碼。并且用戶名、密碼是必須,若為空,則提示錯誤信息。
A、服務器段驗證
1、修改FormBean
我們以前的是繼承ActionForm,現在改成ValidatorForm,導入相應的包,并刪除validator和reset方法。
2、修改struts-config.xml文件,具體代碼如下:
<action
path="/login"
name="loginActionForm"
scope="request"
type="org.zhoudq.webapp.action.LoginAction"
validate="true"
input="/login.jsp">
<forward name="success" path="/success.jsp" />
<forward name="error" path="/wrong.jsp" />
</action>
將validator改為true,告訴服務器對這個表單進行驗證,input的值,是告訴服務器如果嚴整失敗的話,將跳轉的頁面。
3、添加驗證規則
在WEB-INF下創建validaton.xml這個文件,導入引用的dtd,添加如下內容:
<form-validation>
<formset>
<form name="loginActionForm">
<field property="username" depends="required">
<arg key="label.username" />
</field>
<field property="userpass" depends="required">
<arg key="label.password" />
</field>
</form>
</formset>
</form-validation>
3、修改Resource Boundle文件:
英文的資源文件:applicationResource_en_US.properties
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.maxlength={0} can not be greater than {1} characters.
errors.invalid={0} is invalid.
errors.byte={0} must be a byte.
errors.short={0} must be a short.
errors.integer={0} must be an integer.
errors.long={0} must be a long.
errors.float={0} must be a float.
errors.double={0} must be a double.
errors.date={0} is not a date.
errors.range={0} is not in the range {1} through {2}
errors.creditcard={0} is an invalid credit card number.
errors.email={0} is an invalid e-mail address.
button.submit=Submit
button.reset=Reset
button.cancel=Cancel
label.username=UserName:
label.password=Password:
loginform.error.username=please enter your username
loginform.error.password=please enter your password
loginform.fail=invalidation name and password,login error!
中文的資源文件:applicationResource_zh_CN.properties
errors.required={0} 是必須的.
errors.minlength={0} 不能少于 {1} 個字符.
errors.maxlength={0} 不能多于 {1} 個字符.
errors.invalid={0} 是非法的.
errors.byte={0} 必須是 byte 類型.
errors.short={0} 必須是 short 類型.
errors.integer={0} 必須是 Integer 類型.
errors.long={0} 必須是 long 類型.
errors.float={0} 必須是 float 類型.
errors.double={0} 必須是 double 類型.
errors.date={0} 不是一個日期.
errors.range={0} 不在 {1}- {2} 之間.
errors.creditcard={0} 是一個非法的身份證號r.
errors.email={0} 是一個非法的油箱地址.
button.submit=確定
button.reset=重置
button.cancel=取消
label.username=用戶名:
label.password=密碼:
loginform.error.username=請輸入用戶名
loginform.error.password=請輸入密碼
loginform.fail=用戶名或密碼錯誤,登錄失敗!
5、在struts-config.xml添加validator
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validator.xml"/>
</plug-in>
5、運行
打開IE,鍵入:http://localhost:8080/Struts1_Login/login.jsp,直接點確定,如下圖:
B、客戶端驗證
這也表現了Validator驗證框架的強大之處,又服務器生成javascript腳本,這樣就直接在客戶端進行驗證了,從而減少了服務器的壓力,萬事有力又有避,這中方式服務器在生成腳本的同時又犧牲能性能,呵呵,看如何實現吧,一定很振奮吧.
1) 修改login.jsp頁面
<%@ page contentType="text/html; charset=GBK"%>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<html:html>
<head><title>login</title></head>
<body bgcolor="#ffffff">
<h1>login</h1>
<div>
<font color="red">
<html:messages id="error">
<li><bean:write name="error"/></li>
</html:messages>
</font>
</div>
<html:javascript formName="loginActionForm" />
<html:form action="login.do" onsubmit="return validateLoginActionForm(this);">
<bean:message key="label.username"/>
<html:text property="username" />
<br />
<bean:message key="label.password"/>
<html:text property="userpass" />
<br>
<html:submit property="submit"><bean:message key="button.submit"/></html:submit>
<html:reset><bean:message key="button.reset"/></html:reset>
</html:form>
</body>
</html:html>
a)<html:javascript formName="loginActionForm" />表示生成js代碼,formName屬性指定驗證表單的名字,必須和struts-config.xml里面的form一樣。
b)<html:form action="login.do" onsubmit="return validateLoginActionForm(this);">
當用戶提交表單的時候,就會調用<html:javascript>標簽生成的javascript腳本的方法,從而執行客戶端的驗證,其中的LoginActionForm是你FormBean的名字對用,必須和struts-config.xml里面的form一樣,在這里面第一個字母大寫哦。
2)運行測試:
打開IE,鍵入:http://localhost:8080/Struts1_Login/login.jsp,直接點確定,如下圖:
簡單嗎?嘿嘿,兩步就搞定了吧。希望大家繼續關注我哦。
一、概念
I18N作為“國際化”的簡稱,其來源是明文單詞“internationlization”的首末字符“i”和“n”之間的字符數為18。隨著全球經濟的遺體化為一種主流的趨勢,軟件開發者應該開發出支持多國語言、國家化的web應用程序吧。也就是一個web應用程序在運行時能夠根據客戶端請求所來自的國家和語言的不同顯示不同的用戶界面。這樣,當需要在應用程序中添加對一種新的語言的支持時,不需要對已有的軟件返工,無需修改應用程序的程序代碼。
二、Struts對國家化的支持
在Struts框架中進行應用程序的國際化,支持重點在于應用程序的文本和圖像表示。最重要的工作就是準備Resurce Bundle 資源包。事實上,準備資源包的過程,就是把對應不同語言的用戶所涉及的文本和圖片保存在多個文本文件中,客戶端根據不同的環境需要進行更換。這些文件被稱為“屬性文件”,所有屬性文件合在一起被稱為資源包(Resource Bundle)。
Struts建立于Java平臺之上,很容易建立國際化和本地化的應用程序。在這里你要熟悉的關鍵概念是:
1) Locale – 基礎的支持國際化的java類是java.util.Locale。每個Locale代表一個特別的國家和語言的選擇(加上一個可選的語言變量),以及一套格式假定,例如數字和日期等等。
2) ResourceBundle – java.util.ResourceBundle類提供支持多種語言消息的基本工具。查看文檔中關于ResourceBundle類以及你的JDK版本的文檔包中關于國際化的更多內容。
3) PropertyResourceBundle – 一個ResourceBundle類的標準實現允許你使用與初始化properties文件同樣的鍵/值的語法來定義資源。這對于使用為用于一個web應用程序的消息準備資源包是非常方便的,因為這寫消息通常都是面向文本的。
4) MessageFormat – java.text.MessageFormat類允許你使用運行時的指定的參數替換一個消息字符串中的一部分(在這種情況下,是一個從一個資源包得到的消息)。這在你創建一個句子的場合中是有用的,但是詞會以不同的語言安照不同的順序出現。消息中的占位符,字符串{0}用第一個運行時參數替換,{1}用第二個運行時參數替換,以此類推。
5) MessageResources – Struts的類org.apache.struts.util.MessageResources使你能夠將一套資源包視做一個數據庫,并且允許你為一個特定的Locale(通常是與當前用戶相對應)請求一個特定的消息,而不是為服務器運行在其中的缺省的Locale請求消息。
三、示例
1、我們還在前面的登錄實例進行加工。
2、在默認的applicationResources.properties文件中添加相應的消息文本。
label.username=username
label.password=password
button.submit=submit
button.reset=reset
3、創建臨時中文資源文件:applicationResources_temp.propertyies
label.username=用戶名
label.password=密碼
button.submit=確定
button.reset=重置
4、對臨時資源文件進行編碼轉換:
在JDK中提供了native2ascii命令,它能夠實現字符編碼轉換。在DOS下執行以下命令,將生成按GBK以編碼的中文資源文件:applicationResources_zh_CN.properties
native2ascii –encoding gbk applicationResources_temp.properties
applicationResources_zh_CN.properties
生成的applicationResources_zh_CN.properties的內容如下:
label.username="u7528"u6237"u540d
label.password="u5bc6"u7801
button.submit="u786e"u5b9a
button.reset="u91cd"u7f6e
當web用戶的Locale為中文時,Struts框架將自動選擇來自applicationResources_zh_CN.properties文件的消息文本。
5、創建英文的資源文件:
label.username=username
label.password=password
button.submit=submit
button.reset=reset
完成以上幾個步驟后,在web 應用程序的根目錄"WEB-INF目錄"classes目錄下應該有了三個資源文件:
默認資源文件:applicationResource.properties
中文資源文件:applicationResource_zh_CN.properties
英文資源文件:applicationResource_en.properties
6、創建struts的Resource Bundle
Struts配置文件中的<message-resources>元素定義了一個Resource Bundle。Resource Bundle的持久化消息文本存儲在資源文件中,其擴展名為“.properties”,里面存放的都是“鍵/值”。
在struts-config.xml中對Resource Bundle的配置代碼:
<message-resources parameter=”ApplicationResources”/>
表示默認的資源文件應該是applicationResources.properties,存放在應用程序的根目錄"WEB-INF目錄"classes目錄下。如果應用程序需要支持中文用戶,要在相同目錄下創建一個包涵中文消息的資源文件,文件名必須為applicationResource_zh_CN.properties。
7、修改login.jsp頁面
<html:form action="login.do" method="post">
<bean:message key="label.username"/>
<html:text property="username" /><html:errors property="username"/>
<br />
<bean:message key="label.password"/>
<html:text property="userpass" /><html:errors property="userpass"/>
<br>
<input type="submit" name="Submit" value="<bean:message key="button.submit"/>">
<input type="reset" value="<bean:message key="button.reset"/>">
</html:form>
<bean:message/>:用于訪問web應用資源的bean標簽,顯示Resource Boundle中的內容。
8、運行程序
1)如果你的瀏覽器默認設置為中文,你鍵入地址,將看到的頁面如下:
2)把你的瀏覽器的設置為英文,然后刷新頁面,如下圖:
總結:國際化對于web應用程序來說很重要,如果你的web應用程序面對多個國家的話,要實現不同語言的切換,如果不使用國際化的話要么只有一種語言,要么在程序里面改,現在一切都方面了,不過java對中文的支持并不好,并不是什么地方都可以使用中文的,如在LookUpDispatchAction中就不能使用國際化哦。
請關注本人csdn:http://blog.csdn.net/xmh517/
效果圖:
我們以結果為導向,首先大家先看看要完成的效果圖,對接下來要做的事情有個清晰的認識。
1、如圖鍵入:
顯示結果如下圖:
如果您輸入的是不合法的話,則如下圖:
修改步驟:
A、數據源配置
在struts-config.xml文件中有一<data-sources>元素是用來配置應用所需要的數據源,數據源負責建立和特定數據庫的連接,許多數據源采用連接池的機制實現,即提高了數據庫的訪問性能。具體代碼片段如下所示:
<data-sources>
<data-source key="DataSource" type="org.apache.commons.dbcp.BasicDataSource">
<set-property property="driverClassName" value="com.mysql.jdbc.Driver" />
<set-property property="url" value="jdbc:mysql://localhost:3306/struts1_login"/>
<set-property property="username" value="root"/>
<set-property property="password" value="5ihpp1314"/>
</data-source>
</data-sources>
上面這段代碼配置了與MySQL數據庫的連接。<data-source>元素的key是一個別名,用于在應用程序中去的一個連接,元素type用來指定數據源的實現類。上面使用的是Apache軟件組織提供的DBCP數據源。所以你必須導入commons-dbcp.jar、commons-pool.ar、struts-legacy..jar這三個包和MySQL的驅動包:mysql-connector-java-5.0.5-bin.jar。
配置了數據源后,就可以在Action中訪問數據源了。
代碼如下所示:
//獲取Servlet上下文對象
ServletContext ctx = servlet.getServletContext();
//獲得數據源
DataSource ds = (DataSource) ctx.getAttribute("DataSource");
//獲取數據庫的連接
Connection conn = ds.getConnection();
B、修改Action
Action將取得數據源,得到一個數據庫的連接,把頁面傳近來的用戶名和密碼,通過jdbc與數據庫進行對比,如果存在轉到“success.jsp”并顯示其名稱,否則到錯誤頁面。
具體實現代碼如下所示:
public class LoginAction extends Action {
public ActionForward execute(ActionMapping actionMapping,
ActionForm actionForm, HttpServletRequest request,
HttpServletResponse response) {
LoginActionForm loginform = (LoginActionForm) actionForm;
String username = loginform.getUsername();
String userpass = loginform.getUserpass();
ServletContext ctx = servlet.getServletContext();
DataSource ds = (DataSource) ctx.getAttribute("DataSource");
boolean flag = false;
String sql = "select * from user where username='" + username
+ "' and password='" + userpass + "'";
try {
Connection conn = ds.getConnection();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
while (rs.next()) {
flag = true;
}
} catch (Exception e) {
e.printStackTrace();
}
String actionpath = "";
if (flag) {
request.setAttribute("username", username);
actionpath = "success";
} else {
actionpath = "error";
}
return actionMapping.findForward(actionpath);
}
}
C、修改頁面
如果登錄成功,通過EL顯示用戶名。
具體代碼如下:
<%@ page contentType="text/html; charset=GBK" %>
<%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html>
<head>
<title>
success
</title>
</head>
<body bgcolor="#ffffff">
<h1>success.jsp demo</h1>
<br>
<h1>welcome
<font color="red" size="8"><bean:write name="username"/></font>
here,thanks
</h1>
</body>
</html>
引入struts的標簽,輸出用戶名稱。
小結:怎么樣出來你要的結果了吧,不過是使用的數據源配置,我個人認為讓struts來管理不是太妥當,因為數據的相關操作應該屬于持久層的管理,不應該由上一層管理(Controller),所以實際操作中建議不要這么做。
在進行web應用程序開發的過程中,中文問題經常困擾著很多程序員。因此,在接下來的兩個課程的學習中,我將根據實踐經驗來談一下web應用中的中文問題的解決方法。讓大家不再為此而頭痛。
我們就前那個登錄驗證的例子,進行進階,處理中文亂碼問題。前面例子中,只要用戶名和密碼都是123,才返回成功的頁面。為了處理中文,我們判斷只有用戶名是張三才登陸成功。
一、程序進階:
既然是中文亂碼處理,頁面的用戶輸入就是中文了,相應的action的if處理也要變成: if (username.equals("張三") && userpass.equals("123"));
效果圖:
我們以結果為導向,首先大家先看看要完成的效果圖,對接下來要做的事情有個清晰的認識。
1、如圖鍵入:中文
顯示結果如下圖:
為什么會到錯誤頁面呢?我們明明都寫正確了呀,是的,沒有錯誤,這是什么原因呢?
請看下圖:
我們打印才發現原來username的值傳到action中,成了亂碼,這主要由于客戶端和服務器端采用了不同的字符集,中文亂碼我們沒有處理。
二、解決辦法:
A、直接轉編碼
我們新建一個包,命名為util,在包下新建一個類文件,命名為EncodingUtil,類的功能就是提供一個字符集轉換的一個方法,具體代碼如下所示:
package util;
public class Encoding {
public static String isToGB(String src) {
String strRet = null;
try {
strRet = new String(src.getBytes("ISO_8859_1"), "GBK");
} catch (Exception e) {
e.printStackTrace();
}
return strRet;
}
}
小結:這辦法雖然能解決中文亂碼,但是每次還得調用,是不是很不方便呢?如果忘記了調用這個方法,那程序又亂碼了,維護起來很困難,下面我們看另一種解決方案。
B、繼承RequestProcessor類
RequestProcessor類處理ActionServlet接收到的所有請求。根據它的處理方式,可將每個請求分解為多個小任務,分別由不同的方法執行。這就允許針對請求的各個單獨部分自定義處理。
RequestProcessor類的部分方法如下:
processPath(): 獲取客戶端請求的路徑URI
processMapping(): 根據請求URI獲取所需的映射信息
processRoles(): 檢查用戶的角色是否允許他訪問請求的資源
processActionForm(): 新建一個Form Bean或從請求會話中檢索Form Bean
processForward(): 處理<action-mapping>元素forward以匹配當前的請求路徑
processValidate(): 調用Form Bean的validate()方法
processPreprocess(): 告訴請求處理器調用此方法后,是否應繼續處理請求
processLocale(): 為請求選擇一個語言環境
processActionCreate(): 實例化當前ActionMapping指定的類的實例
processActionPerform(): 將調用action的perform()或execute()方法
呵呵,發沒發現RequestProcess類的所有方法都有一個前綴proess,接著往下看吧。
RequestProcessor在action之前,所以我們應著手RequestProcessor,要開發自己的RequestProcessor類,步驟如下:
(1) 創建一個繼承org.apache.struts.action.RequestProcessor的類,在改類中顯示定義一個無參,方法體為空的構造器。
(2) 重寫所需的方法,加入我們的功能。
具體代碼如下所示:
package servlets;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.RequestProcessor;
public class EncodingHandler extends RequestProcessor {
public boolean processPreprocess(HttpServletRequest servletRequest,
HttpServletResponse serveltResponse) {
try {
servletRequest.setCharacterEncoding("GBK");
System.out.println("請求被處理.");
} catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}
return true;
}
}
(3) 修改配置文件sturts-config.xml,在其中加入一個名為<controller>的元素,用以指定我們定制的RequestProcessor類。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean name="loginActionForm" type="formbeans.LoginActionForm" />
</form-beans>
<action-mappings>
<action
path="/login"
name="loginActionForm"
scope="request"
type="actions.LoginAction">
<forward name="success" path="/success.jsp"/>
<forward name="error" path="/wrong.jsp"/>
</action>
</action-mappings>
<controller processorClass="servlets.EncodingHandler" />
</struts-config>
上面就是我們自己的定義的RequestProcessor類,使用<controller>標簽類定義。
如圖:
小結:這樣做呢?問題是解決了,每一個請求先經過這個方法,并轉換了字符集再交給action做處理,這樣我們不用在操心中文亂碼,但RequestProcessor是與struts耦合在一塊兒。如果不用struts框架,我們又該如何處理中文問題呢?是否又更好的辦法呢?那就接著跟我往下看吧。
C、Filter來解決中文問題
Filter,是不是你腦子里閃現了這個詞呢?下面就來看看如何用它來改寫我們上一章節的例子吧!
(1) 首先在工程中新建一包,命名為filter,在下面新建一類文件,命名為EncodingServlet,并繼承HttpServlet、實現Filter接口,注意并實現接口的方法。
在Servlet中filter起著過濾器的作用,當一個請求發送到服務器的時候,需要把請求首先交給filter來處理,然后交給action做處理。EncodingServlet負責處理請求的字符集,在此就起這么個功能,具體代碼請依照如下所示:
package servlets;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
public class EncodingServlet extends HttpServlet implements Filter {
private static final long serialVersionUID = 1L;
public void doFilter(ServletRequest servletRequest,
ServletResponse serveltResponse, FilterChain filterChain) {
try {
servletRequest.setCharacterEncoding("GBK");
filterChain.doFilter(servletRequest, serveltResponse);
} catch (Exception ex) {
}
}
public void init(FilterConfig arg0) throws ServletException {
}
}
(2) 修改web.xml,加入我們的filter。
<filter>
<filter-name>EncodingServlet</filter-name>
<filter-class>servlets.EncodingServlet</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingServlet</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
小結:這個中文亂碼處理用了fileter,而且適用與任何場合,比較實用。
怎么樣,通過三個處理中文亂碼的方案,有和感想呀,是不是程序很有意思呀,那就跟著我繼續看看struts別的東東吧……
請關注本人csdn:http://blog.csdn.net/xmh517/
Struts是一個基于Sun J2EE平臺的MVC框架,主要是采用Servlet和JSP技術來實現的。由于Struts能充分滿足應用開發的需求,簡單易用,敏捷迅速,在過去的幾年中頗受關注。Struts把Servlet、JSP、自定義標簽和信息資源(message resources)整合到一個統一的框架中,開發人員利用其進行開發時不用再自己編碼實現全套MVC模式,極大的節省了時間,所以說Struts是一個非常不錯的應用框架。很多公司開發的產品都是基于此框架的。
當然,有朋友一提起編程就覺得頭痛,是否如此呢?我想通過本期的struts教程,你便會有自己的結論喲!
本期struts教程本著從易用、實用的目的出發,帶您手把手地完成公司開發中常用模塊的開發,使你迅速上手struts。
主要通過以下六個模塊:
一、登錄驗證實例
二、解決中文亂碼問題實例
三、連數據庫實例
四、國際化
五、驗證數據實例
六、模塊使用實例
七、制作簡單留言板實例
使大家對struts能由淺入深的學習,最終撐握它。
萬事開頭難,就讓我們一起來經歷struts的開發吧,經過本系列的學習,你肯定能很快地駕馭它。給自己多幾分信心吧!
閑話不多說,接下來就開始實戰吧!!
一、普通的登錄驗證實例
效果圖:
我們以結果為導向,首先大家先看看要完成的效果圖,對接下來要做的事情有個清晰的認識。
1、如圖鍵入:
顯示結果如下圖:
如果您輸入的是合法的話,則如下圖:
開發步驟:
A、首先建立一工程,選擇web模塊,最后再加載struts包即可。在工程中新建一包,命名為actions,在下面新建一類文件,命名為LoginAction,里面一定要重寫execute方法,注意參數的順序及返回類型都是不可以變化的。
在struts中action類起著控制轉向的作用,當我們輸入用戶名與密碼并點了提交按鈕后,需要交給控制器來決斷我們是轉向到登陸成功頁還是登陸失敗頁。LoginAction在此就起這么個功能,具體代碼請依照如下所示:
public class LoginAction extends Action {
public ActionForward execute(ActionMapping actionMapping,
ActionForm actionForm,
HttpServletRequest servletRequest,
HttpServletResponse serveltResponse) {
LoginActionForm loginform = (LoginActionForm) actionForm;
String username = loginform.getUsername();
String userpass = loginform.getUserpass();
boolean flag = false;
String actionpath = "";
if (username.equals("123") && userpass.equals("123")) {
actionpath = "success";
} else {
actionpath = "error";
}
return actionMapping.findForward(actionpath);
}
}
在“LoginAction”中,我們得到一個ActionForm對象,并把它強轉成LoginActionForm,
待我們處理,即通過ActionForm的匹配名稱的表單自動封裝機制,取得用戶輸入用戶名、密碼。
我們返回的結果將會被ActionFormward對象所包裝,比如這兒的“success“表示用戶合法,“error”表示用戶不合法,這個字符串將決定著頁面的流程控制。它并不是一個具體存在的頁面,它是如何跟一個具體的頁面關聯上的呢?
呵呵,先不要急,我們來分析幾點:
1、 你在操作時記住的概念:
Struts的核心是Action,而Action的核心就是一個配置文件——struts-config.xml。它既然是核心就很重要哦。
2、 Maping映射:
a) actionMapping.findForward(“映射名稱”); 它返回的是一個ActionForward對象
b) struts-config.xml里面action節點下的:<forward name="映射名稱" path="/頁面名稱"/>
實現機制:Struts會根據你傳進actionMapping.findForward(“映射名稱”),它會到你當前action節點下去找forward這個節點,并把你傳進的參數與這個節點的name屬性進行匹配。如果相等它就會跳到這個節點的path所指定的頁面。
例:
Action:actionMapping.findForward(“success”)
Struts-config.xml:<forward name="success" path="/success.jsp"/>
如果是這種情況的話,它就會轉發到success.jsp頁面。
注意:
a) 方法的參數值和name節點的值對應,
b) Path所指定的頁面,前面必須加上“/“
B、在前面我們提到了ActionForm,所以我們還需要建立一個類文件,這個類文件將封裝頁面用戶輸入的用戶名、和密碼。
注意:
1、這個類必須繼承ActionForm類,它將完成與頁面的自動封裝。
2、類中的屬性名稱一定要和頁面的輸入框的名稱對應,為了自動封裝的匹配工作。
3、這個類中一定要提供所有與屬性相匹配的set 和 get方法。
好,前面寫了這些代碼,看上去還是有些雜亂無章,怎么把它們關聯起來呢?又怎么調用這些代碼呢?呵呵,群龍不會無首的,下面就一起來關注struts的裝配文件,它可是相當于struts的總司令喲!
C、核心部分,跳轉控制Struts-config.xml部分
<struts-config>
<form-beans>
<form-bean name="loginActionForm" type="formbeans.LoginActionForm" />
</form-beans>
<action-mappings>
<action path="/login" name="loginActionForm" type="actions.LoginAction">
<forward name="success" path="/success.jsp"/>
<forward name="error" path="/wrong.jsp"/>
</action>
</action-mappings>
</struts-config>
我們對struts.xml做一下相應的介紹吧,如下:
<form-bean>:用來配置一個ActionForm Bean。常用配置的幾個屬性:
name:指定該ActionForm Bean的唯一標識符,整個Struts框架用該標識符來引用這個Bean。該屬性是必需的
type:指定ActionForm類的全限定名。該屬性是必需的
<action>:用來描述特定的請求路徑到相應的Action類的映射。常用配置的幾個屬性:
input: 指定包含輸入表單的URL路徑。當表單驗證失敗時,將把請求轉發到該URL。
name: 指定和該Action關聯的ActionForm Bean的名字。
path: 指定訪問Action的路徑,它以“/”開頭,沒有擴展名。
Scope: 指定ActionForm Bean的存在范圍。(session | request)
Validate:指定是否要先調用ActionForm Bean的validate()方法。默認值為true
Action的子元素<forward>常用配置的幾個屬性:
name: 指定轉發路徑的邏輯名。必需的
path: 指定轉發(或重定向)的URI,必須以”/”開頭。必需的
redirect:當此項為true時,表示執行重定向操作。為false時表示執行請求轉發操作。默認值為false
D、頁面login.jsp,用戶登錄頁面,提供用戶輸入功能。具體代碼如下所示:
<form method="post" action="login.do">
請輸入姓名:<input type="text" name="username" value=""/><br />
請輸入密碼:<input type="password" name="userpass" value=""/><br>
<input type="submit" name="Submit" value="Submit">
<input type="reset" value="Reset">
</form>
注意:
1、action后面的login.do就是struts-config.xml里面你要訪問的action節點path的值哦
2、切記哦,如果你請求的URL的引用了formbean的話,這里的名稱一定要對應哦。
還有success.jsp 、wrong.jsp分別代表登錄成功和登錄失敗頁面。就不再多說啦!
啟動Tomcat,連接上您的應用程序網址,例如:http://localhost:8080/Struts1_Login/login.jsp,填入用戶名、密碼,并送出窗體,您的歡迎頁面就會顯示了。
怎么樣,本章節是不是比較容易?其實struts就這么簡單,能完成本章節的要求吧!現在你已經上手啦,接著往下學,我們會有越來越多的收獲喲!!
請關注本人csdn:http://blog.csdn.net/xmh517/