posted @ 2010-03-01 22:58 長(zhǎng)城 閱讀(5808) | 評(píng)論 (5) | 編輯 收藏
posted @ 2010-03-01 15:01 長(zhǎng)城 閱讀(2440) | 評(píng)論 (0) | 編輯 收藏
posted @ 2010-03-01 12:01 長(zhǎng)城 閱讀(2950) | 評(píng)論 (0) | 編輯 收藏
posted @ 2010-02-27 21:31 長(zhǎng)城 閱讀(4787) | 評(píng)論 (4) | 編輯 收藏
一、創(chuàng)建 Android工程
Project name:SendMessage
BuildTarget:Android2.1
Application name:發(fā)送短信
Package name:com.changcheng.Activity
Create Activity:SendMessage
Min SDK Version:7
二、編輯工程
1.編輯strings.xml文件內(nèi)容為:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">請(qǐng)輸入手機(jī)號(hào)碼:</string> <string name="app_name">發(fā)送短信</string> <string name="content">請(qǐng)輸入信息內(nèi)容:</string> <string name="send">發(fā)送</string> </resources> |
2.編輯main.xml文件內(nèi)容為:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <!-- 請(qǐng)輸入手機(jī)號(hào)碼標(biāo)簽 --> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <!-- 手機(jī)號(hào)碼編輯框 --> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/mobile" /> <!-- 請(qǐng)輸入信息內(nèi)容標(biāo)簽 --> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/content" /> <!-- 信息內(nèi)容編輯框 --> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:minLines="3" android:id="@+id/message" /> <!-- 發(fā)送按鈕 --> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/send" android:id="@+id/send"/> </LinearLayout> |
注意,我們?cè)陔娫捥?hào)碼輸入框和撥打電話按鈕中添加了android:id屬性。如電話號(hào)碼輸入框的android:id=”@+id/mobile”,@代碼R.java,+id代碼添加id靜態(tài)內(nèi)部類,mobile代表向id類中添加一個(gè)常量成員。ADT將自動(dòng)為我們生成常量值。
android:minLines設(shè)置信息內(nèi)容編輯框的最小行數(shù)。
3.編輯Call.java內(nèi)容:
package com.changcheng.activity;
import java.util.List; import android.app.Activity; import android.os.Bundle; import android.telephony.SmsManager; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText;
public class SendMessage extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 根據(jù)ID獲取按鈕 Button button = (Button) this.findViewById(R.id.send); // 注冊(cè)按鈕被單擊事件 button.setOnClickListener(new OnClickListener() {
@Override public void onClick(View v) { // 根據(jù)ID獲取手機(jī)號(hào)碼編輯框 EditText mobileText = (EditText) findViewById(R.id.mobile); // 獲取手機(jī)號(hào)碼 String mobile = mobileText.getText().toString(); // 根據(jù)ID獲取信息內(nèi)容編輯框 EditText messageText = (EditText) findViewById(R.id.message); // 獲取信息內(nèi)容 String message = messageText.getText().toString(); // 移動(dòng)運(yùn)營(yíng)商允許每次發(fā)送的字節(jié)數(shù)據(jù)有限,我們可以使用Android給我們提供 的短信工具。 if (message != null) { SmsManager sms = SmsManager.getDefault(); // 如果短信沒(méi)有超過(guò)限制長(zhǎng)度,則返回一個(gè)長(zhǎng)度的List。 List<String> texts = sms.divideMessage(message); for (String text : texts) { sms.sendTextMessage(mobile, null, text, null, null); } } } }); } } |
sms.sendTextMessage(destinationAddress, scAddress, text, sentIntent, deliveryIntent):
destinationAddress:接收方的手機(jī)號(hào)碼
scAddress:發(fā)送方的手機(jī)號(hào)碼
text:信息內(nèi)容
sentIntent:發(fā)送是否成功的回執(zhí),以后會(huì)詳細(xì)介紹。
DeliveryIntent:接收是否成功的回執(zhí),以后會(huì)詳細(xì)介紹。
4.編輯AndroidManifest.xml內(nèi)容:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.changcheng.activity" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".SendMessage" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="7" /> <!-- 注冊(cè)發(fā)送短信的權(quán)限 --> <uses-permission android:name="android.permission.SEND_SMS" /> </manifest> |
注冊(cè)發(fā)送短信的權(quán)限,如果沒(méi)有注冊(cè)這個(gè),將使用不了系統(tǒng)的發(fā)送短信功能。以后在我們的應(yīng)用程序開發(fā)中,有使用到系統(tǒng)功能的必須在這個(gè)文件中進(jìn)行注冊(cè)。我們可以查看Android的幫助手冊(cè)都有哪些功能。(.../android-sdk-windows/docs/reference/android/Manifest.permission.html)
三、啟動(dòng)模擬器
我們給誰(shuí)發(fā)短信?我們可以啟動(dòng)兩個(gè)模擬器。使用一個(gè)模擬器給另一個(gè)模擬器發(fā)信息。首先我們使用工具欄上的手機(jī)圖標(biāo)再添加一個(gè)Android2.1的模擬器,另記一個(gè)名稱。
在啟動(dòng)兩個(gè)模擬器之前,我們需要模擬器能“接收到信號(hào)”。如果我們的機(jī)器是聯(lián)網(wǎng)的,啟動(dòng)模擬器后,主界面顯示信號(hào)強(qiáng)度的旁邊會(huì)有一個(gè)3G的字樣,這說(shuō)明模擬器已經(jīng)能接收到信號(hào)了。如果我們的機(jī)器不能聯(lián)網(wǎng),那么將自己的IP地址、網(wǎng)關(guān)和DNS服務(wù)器都設(shè)置為相同的值,比如都設(shè)置為192.168.0.100。如果我們的機(jī)器是在局域網(wǎng)下,但沒(méi)有聯(lián)網(wǎng),那么將自己的網(wǎng)關(guān)和DNS設(shè)置為路由的IP即可,一般情況下路由的IP是192.168.0.1。
OK,現(xiàn)在我們啟動(dòng)兩個(gè)模擬器!
四、發(fā)送短信
我們啟動(dòng)模擬器后,可以看到模擬器窗口的標(biāo)題欄上有5554和55556的字樣。這是模擬器監(jiān)聽的端口即——127.0.0.1:5554。
在工程上右鍵,Run As Android Application,選擇其中的一個(gè)模擬器。比如選擇了端口為5554的模擬器。OK,程序被加載到模擬器中了,會(huì)被自動(dòng)運(yùn)行。
我們?cè)陔娫捥?hào)碼編輯框中輸入5556(接收端模擬器的端口號(hào)),點(diǎn)擊發(fā)送按鈕!
OK,你看到效果了嗎?5556主界面,顯示信號(hào)強(qiáng)度的旁邊顯示收到新短信。
五、使用ADT插件發(fā)送短信給模擬器
如果機(jī)器太慢,無(wú)法啟動(dòng)兩個(gè)模擬器,我們可以只啟動(dòng)一個(gè)模擬器。然后在菜單windows->show view->other->Android->Emulator Control打開Emulator Control面板。
Telephony Actions分組框中,Voice是呼叫,SMS是發(fā)送短信。Incoming number是模擬器的端口號(hào),我們也可以使用這個(gè)功能給我們的模擬器撥打電話或發(fā)送短信。
posted @ 2010-02-27 00:20 長(zhǎng)城 閱讀(3508) | 評(píng)論 (0) | 編輯 收藏
一、創(chuàng)建 Android工程
Project name:Call
BuildTarget:Android2.1
Application name:撥打電話
Package name:com.changcheng.Activity
Create Activity:Call
Min SDK Version:7
二、編輯工程
1.編輯strings.xml文件內(nèi)容為:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">請(qǐng)輸入 手機(jī)號(hào)碼:</string> <string name="app_name">撥打電話</string> <string name="button_call">呼叫</string> </resources> |
2.編輯main.xml文件內(nèi)容為:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <!-- 標(biāo)題標(biāo)簽 --> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <!-- 電話號(hào)碼輸入框 --> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/mobile"/> <!-- 撥打電話按鈕 --> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_call" android:id="@+id/button_call"/> </LinearLayout> |
注意,我們?cè)陔娫捥?hào)碼輸入框和撥打電話按鈕中添加了android:id屬性。如電話號(hào)碼輸入框的android:id=”@+id/mobile”,@代碼R.java,+id代碼添加id靜態(tài)內(nèi)部類,mobile代表向id類中添加一個(gè)常量成員。ADT將自動(dòng)為我們生成常量值。
3.編輯Call.java內(nèi)容:
package com.changcheng.Activity;
import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText;
public class Call extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 根據(jù)ID獲取按鈕 Button button = (Button) this.findViewById(R.id.button_call); // 為按鈕添加被單擊事件 button.setOnClickListener(new OnClickListener(){
@Override public void onClick(View v) { // 根據(jù)ID獲取編輯框 EditText editText = (EditText) findViewById(R.id.mobile); // 獲取電話號(hào)碼 String mobile = editText.getText().toString(); // 生成呼叫意圖 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+ mobile)); // 開始呼叫 startActivity(intent); } }); } } |
4.編輯AndroidManifest.xml內(nèi)容:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.changcheng.Activity" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".Call" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
</application> <uses-sdk android:minSdkVersion="7" /> <!-- 注冊(cè)使用撥打電話功能的權(quán)限 --> <uses-permission android:name="android.permission.CALL_PHONE"/> </manifest> |
注冊(cè)使用撥打電話功能的權(quán)限,如果沒(méi)有注冊(cè)這個(gè),將使用不了系統(tǒng)的撥打電話功能。以后在我們的應(yīng)用程序開發(fā)中,有使用到系統(tǒng)功能的必須在這個(gè)文件中進(jìn)行注冊(cè)。我們可以查看Android的幫助手冊(cè)都有哪些功能。(.../android-sdk-windows/docs/reference/android/Manifest.permission.html)
三、啟動(dòng)模擬器
我們給誰(shuí)打電話?我們可以啟動(dòng)兩個(gè)模擬器。使用一個(gè)模擬器給另一個(gè)模擬器撥打。首先我們使用工具欄上的手機(jī)圖標(biāo)再添加一個(gè)Android2.1的模擬器,另記一個(gè)名稱。
在啟動(dòng)兩個(gè)模擬器之前,我們需要模擬器能“接收到信號(hào)”。如果我們的機(jī)器是聯(lián)網(wǎng)的,啟動(dòng)模擬器后,主界面顯示信號(hào)強(qiáng)度的旁邊會(huì)有一個(gè)3G的字樣,這說(shuō)明模擬器已經(jīng)能接收到信號(hào)了。如果我們的機(jī)器不能聯(lián)網(wǎng),那么將自己的IP地址、網(wǎng)關(guān)和DNS服務(wù)器都設(shè)置為相同的值,比如都設(shè)置為192.168.0.100。如果我們的機(jī)器是在局域網(wǎng)下,但沒(méi)有聯(lián)網(wǎng),那么將自己的網(wǎng)關(guān)和DNS設(shè)置為路由的IP即可,一般情況下路由的IP是192.168.0.1。
OK,現(xiàn)在我們啟動(dòng)兩個(gè)模擬器!
四、撥打電話
我們啟動(dòng)模擬器后,可以看到模擬器窗口的標(biāo)題欄上有5554和55556的字樣。這是模擬器監(jiān)聽的端口即——127.0.0.1:5554。
在工程上右鍵盤,Run As Android Application,選擇其中的一個(gè)模擬器。比如選擇了端口為5554的模擬器。OK,程序被加載到模擬器中了,會(huì)被自動(dòng)運(yùn)行。
我們?cè)陔娫捥?hào)碼編輯框中輸入5556(接收端模擬器的端口號(hào)),點(diǎn)擊呼叫按鈕!
OK,你看到效果了嗎?5554模擬器顯示正在呼叫,5556模擬器有來(lái)電顯示...。
五、使用ADT插件呼叫模擬器
如果機(jī)器太慢,無(wú)法啟動(dòng)兩個(gè)模擬器,我們可以只啟動(dòng)一個(gè)模擬器。然后在菜單windows->show view->other->Android->Emulator Control打開Emulator Control面板。
Telephony Actions分組框中,Voice是呼叫,SMS是發(fā)送短信。Incoming number是模擬器的端口號(hào),我們也可以使用這個(gè)功能給我們的模擬器撥打電話或發(fā)送短信。
posted @ 2010-02-26 23:00 長(zhǎng)城 閱讀(3715) | 評(píng)論 (0) | 編輯 收藏
posted @ 2010-02-26 21:21 長(zhǎng)城 閱讀(5351) | 評(píng)論 (2) | 編輯 收藏
我今天用Struts2與Spring整合,但部署到Tomcat(tomcat-6.0.20)時(shí),WabAppClassLoader卻給我拋出了一個(gè)異常:ClassNotFindException:xxx.ActionServlet。ActionServlet是Struts1中使用的Action控制器。但我使用的是Struts2??!
我反復(fù)查看自己的配置文件和使用到的Jar包,沒(méi)有任何問(wèn)題。然后到網(wǎng)上搜索答案,出現(xiàn)這個(gè)問(wèn)題的人還不少。有的是使用Strut1出現(xiàn)這個(gè)問(wèn)題,那么他可能是沒(méi)有導(dǎo)入Struts1的核心包導(dǎo)致的。至于使用Struts2也出現(xiàn)這個(gè)問(wèn)題多少就有些奇怪了。
一些網(wǎng)友給出答案,是將Tomcat刪除,然后安裝一個(gè)新的Tomcat這樣就可以解決問(wèn)題。確實(shí)如此,我使用這個(gè)方法解決了問(wèn)題。但為什么會(huì)出現(xiàn)這個(gè)問(wèn)題呢?我最先想到的是Tomcat可能有緩存功能,于是我查看Tomcat的目錄。發(fā)現(xiàn)它有一個(gè)temp目錄和一個(gè)work目錄,temp目錄是做什么用的我不知道,work目錄是為我們生成JSP的class文件。
問(wèn)題就可能出現(xiàn)在這兩個(gè)目錄,所以以后遇見莫名其妙的問(wèn)題可以刪除這兩個(gè)目錄中的內(nèi)容,然后再試一試。
posted @ 2010-02-25 23:58 長(zhǎng)城 閱讀(444) | 評(píng)論 (0) | 編輯 收藏
Struts2第四天,正如預(yù)期Struts2的內(nèi)容還沒(méi)有講完,還需要再加一天課。按照正常的授課方式,Struts2在四天內(nèi)是可以講完的,但這可能是老張最后一次講Struts2,所以他要講得細(xì)致些。
今天的重點(diǎn)內(nèi)容是Struts2的表單錯(cuò)誤信息排版、Struts2中的FreeMark、和Struts2中的UI標(biāo)簽。老張計(jì)的比較細(xì)致,我做總結(jié)就不做的那么細(xì)致了。
一、Struts2的表單錯(cuò)誤信息排版
Struts2的表單錯(cuò)誤信息排版是一個(gè)比較常見的問(wèn)題,但網(wǎng)給所見到的解決方案似乎并不正統(tǒng)。老張給出了他的解決方法。
通過(guò)之前的學(xué)習(xí),我們知道Struts2中的大部分?jǐn)?shù)據(jù)交互操作是由ValueStack來(lái)完成的。錯(cuò)誤信息也是如此。我們?cè)诤笈_(tái)使用配置文件校驗(yàn)或硬編碼校驗(yàn),Struts2將錯(cuò)誤信息存放在類型為Map的fieldErrors對(duì)象中。
我們可以在頁(yè)面表單字段的后邊添加此錯(cuò)誤信息,比如在user.name表單字段后邊添加<s:property value="fieldErrors['user.name'][0]"/>,這樣錯(cuò)誤信息可以顯示在對(duì)應(yīng)的字段后邊。這是針對(duì)我們使用非struts2的ui標(biāo)簽時(shí)(使用提html的ui標(biāo)簽)。但這里有一個(gè)問(wèn)題,如果我的表單字段特別的多,難道我要手動(dòng)為每個(gè)字段添加一個(gè)這樣的錯(cuò)誤信息,這多少有些麻煩,而且以后字段有什么變化還需要行動(dòng)更改...。
Struts2在各方面都做的非常細(xì)致和人性化,Struts2的UI標(biāo)簽等主要是使用FreeMark來(lái)實(shí)現(xiàn)的。Struts2使用FreeMar來(lái)實(shí)現(xiàn)模板和主題,那么我們回顯表單數(shù)據(jù)和錯(cuò)誤信息也可以使用FreeMark來(lái)實(shí)現(xiàn)。此時(shí)我們的表單需要使用struts-tags提供的標(biāo)簽來(lái)定義,然后我們修改它的ftl模板文件。
下面我們看看一下應(yīng)該如何修改ftl模板文件,我們以UI標(biāo)簽<s:textarea>為例。Struts2的模板文件存在哪?在Struts2的核心包中的template.xhtml中,textarea.ftl文件內(nèi)容:
<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" /> <#include "/${parameters.templateDir}/simple/textarea.ftl" /> <#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" /> |
我們只需修改 controlheader.ftl和controlfooter.ftl即可,難道我們需要修改Struts2核心包中的內(nèi)容?當(dāng)然不用,這一點(diǎn)Struts2已經(jīng)為我們考慮到了。我們將這兩個(gè)文件解壓縮并放到WebRoot目錄下的”template/xhtml”目錄,必須是xhtml目錄???span lang="EN-US">default.properties文件中的這斷配置:
### Standard UI theme ### Change this to reflect which path should be used for JSP control tag templates by default struts.ui.theme=xhtml struts.ui.templateDir=template #sets the default template type. Either ftl, vm, or jsp struts.ui.templateSuffix=ftl |
Struts2會(huì)先到我們的WebRoot目錄搜索相關(guān)ftl文件,如果沒(méi)有才到自己的包中找。
我們的目標(biāo),要使用Struts2的UI標(biāo)簽并將錯(cuò)誤信息顯示在標(biāo)簽的旁邊。所以我們修改這兩個(gè)文件的內(nèi)容為:
controlheader.ftl
<#-- Only show message if errors are available. This will be done if ActionSupport is used. --> <#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/> <#if parameters.labelposition?default("") == 'top'> <td align="left" valign="top" colspan="2"><#rt/> <#else> <td class="tdLabel"><#rt/> </#if> <#if parameters.label??> <label <#t/> <#if parameters.id??> for="${parameters.id?html}" <#t/> </#if> <#if hasFieldErrors> class="errorLabel"<#t/> <#else> class="label"<#t/> </#if> ><#t/> <#if parameters.required?default(false) && parameters.requiredposition?default("right") != 'right'> <span class="required">${stack.findValue("getText('requiredmark')")}</span><#t/> </#if> ${parameters.label?html}<#t/> <#if parameters.required?default(false) && parameters.requiredposition?default("right") == 'right'> <span class="required"><@s.text name="requiredmark"></@s.text></span><#t/> </#if> ${parameters.labelseparator?default(":")?html}<#t/> <#include "/${parameters.templateDir}/xhtml/tooltip.ftl" /> </label><#t/> </#if> </td><#lt/> <#-- add the extra row --> <#if parameters.labelposition?default("") == 'top'> </tr> <tr> </#if> |
controlfooter.ftl
${parameters.after?if_exists}<#t/> </td><#lt/> <#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/> <#if hasFieldErrors> <td ><#rt/> <#list fieldErrors[parameters.name] as error> <span class="errorMessage">${error?html}</span><#t/> </#list> </td><#lt/> </#if> <#-- if the label position is top, then give the label it's own row in the table --> <tr> </tr> |
至于為什么這么修改,一看便知,我就不多做解釋了。
二、Struts2如何使用Freemarker
Struts2是如何使用Freemarker的?在struts2的核心包中有一個(gè)default.properties配置文件,Struts2的默認(rèn)配置都在這個(gè)文件中。有一些配置是開啟的有一些配置是關(guān)閉的。我們要想打開被關(guān)閉的配置可以在struts.xml中,添加<constant name="配置項(xiàng)名" value="配置項(xiàng)值"></constant>元素。
default.properties中有一個(gè)”struts.freemarker.manager.classname=org.apache.struts2.views.freemarker.FreemarkerManager“配置,Struts2是通過(guò)FreemarkerManager類來(lái)實(shí)現(xiàn)對(duì)Freemarker的操作的。
通過(guò)查看源代碼,我們知道通過(guò)調(diào)用FreemarkerManager類的buildTemplateModel方法生成一個(gè)model對(duì)象,然后將這個(gè)對(duì)象放在ValueStack中提供給Freemarker的引擎使用。model中都包含發(fā)哪些數(shù)據(jù)?Freemark的模板信息自然不用說(shuō),它還包含Request、Application、Response等這些在WEB應(yīng)用中常用到的對(duì)象。具體我就不詳細(xì)列出了,大家可以查看源代碼。我們?cè)谏线厓蓚€(gè)模板文件中使用到的 parameters.name也是存儲(chǔ)在model中的。
在此特別提出一個(gè)被叫做UIBean的類型,UIBean就是對(duì)應(yīng)Struts2的UI標(biāo)簽的對(duì)象實(shí)體。比如標(biāo)簽有name、theme、id等數(shù)據(jù),這些都會(huì)被封裝到UIBean中。Freemarker也正是使用這個(gè)東東給我們生成了相應(yīng)該的頁(yè)面文件。
三、Struts2中的UI標(biāo)簽
關(guān)于各UI標(biāo)簽的詳細(xì)使用方式,在此就不做總結(jié)了。
在實(shí)際開發(fā)中有一個(gè)重要的問(wèn)題需要我們解決,比如有一個(gè)選擇個(gè)人喜好的表單。我們需要通過(guò)一個(gè)Action的方法(likesUI)將喜好列表提供給頁(yè)面,可以讓用戶選擇。但在應(yīng)用提交選擇進(jìn)行表單校驗(yàn)時(shí),用戶提交的數(shù)據(jù)不合法,我們需要重新返回到用戶選擇的界面。此時(shí),我們需要調(diào)用 likesUI,獲取列表將數(shù)據(jù)提供給用戶選擇的界面。
我們可以在Action中添加”<result name="input" type="chain">likesUI</result>”,使其發(fā)生錯(cuò)誤時(shí)直接跳轉(zhuǎn)到likesUI,我們也需要在likesUI中添加一個(gè) 名稱為input的result標(biāo)簽,但這個(gè)標(biāo)簽的值不能為likesUI,否則會(huì)遞歸調(diào)用,直到緩存溢出。我們應(yīng)將它的值指定為likesUI.jsp頁(yè)面。但即使指定了這個(gè)頁(yè)面,Struts2的內(nèi)部實(shí)現(xiàn)方式也不會(huì)調(diào)用likesUI方法從,不會(huì)將數(shù)據(jù)傳遞給likesUI.jsp頁(yè)面,而它直接跳轉(zhuǎn)到likesUI.jsp頁(yè)面。
看來(lái)我們不能這么做,通過(guò)張老師對(duì)源代碼的詳細(xì)解析,我們只需要將likesUIAction中的likesUI的方法命名為input(),并只在likeUIAction中添加”<result name="input">/WEB-INF/pages/user/likesUI.jsp</result>“即可。為什么呢?
在表單校驗(yàn)發(fā)生錯(cuò)誤并使用 chain進(jìn)行跳轉(zhuǎn)時(shí),會(huì)被chain攔截器給攔截了(ActionChainResult)。然后又會(huì)被攔截器validation給攔截了,它再進(jìn)行表單校驗(yàn)進(jìn)還是以前的數(shù)據(jù),還是會(huì)出錯(cuò)然后它就直接跳轉(zhuǎn)到我們指定的頁(yè)面了。注意配置文件中的validation:
<interceptor-ref name="validation"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> |
它忽略請(qǐng)求為 input,back,cancel,browse請(qǐng)求路徑。所以我們需要將我們的方法名定義為 input()。
我只是泛泛而結(jié),如果想了解Struts2的更多細(xì)節(jié)請(qǐng)下載老張的視頻看吧!
最后送給大家一個(gè)Struts2開發(fā)用例參考模式圖:
1.用戶申請(qǐng)注冊(cè),打開注冊(cè)頁(yè)面。
2.用戶提交注冊(cè)申請(qǐng),表單校驗(yàn)錯(cuò)誤。
3.表單校驗(yàn)錯(cuò)誤不要跳轉(zhuǎn)到regUser.jsp頁(yè)面,而是應(yīng)該跳轉(zhuǎn)到RegUserUI這個(gè)Action方法。
4.用戶提交注冊(cè)申請(qǐng),表單校驗(yàn)通過(guò)。
5.表單校驗(yàn)通過(guò),調(diào)用RegUser這個(gè)Action方法進(jìn)行注冊(cè)。
6.注冊(cè)成功后,不要跳轉(zhuǎn)到list.jsp頁(yè)面。而是應(yīng)該調(diào)用ListAction這個(gè)Action方法。
7.ListAction獲取所有用戶信息后,跳轉(zhuǎn)到list.jsp。
一定要記得老張還有一天的Struts2的課程,下一次課程的重點(diǎn)內(nèi)容應(yīng)該是Struts2的文件上傳與下載,Struts2的防止表單重復(fù)提交,Struts2與Spring、AJAX整合,Struts2的插件。
接下來(lái)的課程內(nèi)容讓我等的好久啊——Android!雖然聽學(xué)習(xí)過(guò)的同學(xué)們說(shuō)十分簡(jiǎn)單,但我還是迫不及待的想Android的一睹真容。我想很多人都是這樣吧!那就關(guān)注我接下來(lái)6天課程的總結(jié)日志吧!
posted @ 2010-02-25 21:32 長(zhǎng)城 閱讀(584) | 評(píng)論 (0) | 編輯 收藏
Struts2第三天。如果老張他喜歡頭發(fā),他肯定會(huì)把頭上的頭發(fā)有多少根,一根一根的數(shù)出來(lái)。他搞的太細(xì)了!
今天的重點(diǎn)內(nèi)容是國(guó)際化、表單與Action數(shù)據(jù)交互、表單校驗(yàn),不多說(shuō)了開始總結(jié)。
一、Struts2國(guó)際化
在我們學(xué)習(xí)WEB基礎(chǔ)的時(shí)候就講到了國(guó)際化,Struts2中的國(guó)際化實(shí)現(xiàn)方式與我們之前所學(xué)習(xí)到的國(guó)際化相同。但是Struts2中對(duì)國(guó)際化做了強(qiáng)化支持!
我們通過(guò)在struts.xml文件中加入”<constant name="struts.custom.i18n.resources" value="*.properties"></constant>”為指定全局國(guó)際化資源文件。Struts2會(huì)根據(jù)瀏覽器設(shè)置的語(yǔ)言信息運(yùn)行對(duì)應(yīng)的國(guó)際化文件,如果沒(méi)找到就根據(jù)操作系統(tǒng)的語(yǔ)言查找指定的文件,還是沒(méi)有,那就使用默認(rèn)的。我們必須在struts.xml中使用定義在struts-default.xml文件中的defaultStack攔截器堆棧。使用defaultStack我們必須在package中添加extends="struts-default"屬性。如果在我們的Action中沒(méi)有使用任何攔截器,defaultStack默認(rèn)被使用。如果有使用任何其他攔截器,我們必須手動(dòng)加入defaultStack攔截器堆棧。Struts2將使用defaultStack攔截器堆棧中的i18n攔截器,為我們提供國(guó)際化支持。
引入多個(gè)全局資源包的方法是在上面的value屬性中添加以”,”分隔的多個(gè)資源文件。排在最后的資源包的優(yōu)先級(jí)別最高(如果有重復(fù)的資源名稱)。那如果有時(shí)我想在JSP頁(yè)面中使用第一個(gè)資源包中的資源怎么辦?Struts2為我們提供了一個(gè)標(biāo)簽“<s:i18n name="first.properties"></s:i18n>”,在標(biāo)簽體內(nèi)使用到的國(guó)際化資源,全以first.properties為先。
我們可以為每個(gè)Action指定一個(gè)資源包,資源包的名稱與Action的名稱相同。Struts2的國(guó)際化模塊會(huì)先找與Action對(duì)應(yīng)的資源包,如果沒(méi)有就找它上一級(jí)的資源包,就這樣逐級(jí)向上。如果直到類所在包的是后一層目錄也沒(méi)找到就使用全局資源。這有什么好處?我們可能會(huì)有多個(gè)Action使用同一個(gè)或多個(gè)相同的資源,難道我們要在每個(gè)Action對(duì)應(yīng)的資源包里定義它嗎?當(dāng)然不需要,我們只需要把它定義在這幾個(gè)Action的上級(jí)且同一目錄即可。
我們?nèi)绾卧?span lang="EN-US" xml:lang="EN-US">JSP頁(yè)面有使用國(guó)際化資源?Struts2的tags為我們提供了“<s:text name=""></s:text>”標(biāo)簽,它是專門用來(lái)訪問(wèn)國(guó)際化資源的。除此之外我們也可以使用“<s:property value=”getText(key)”>”,這個(gè)getText()是哪來(lái)的?當(dāng)然是ValueStack中的某個(gè)對(duì)象的方法嘍!是類型為com.opensymphony.xwork2.DefaultTextProvider對(duì)象的。Struts2中使用OGNL操作ValueStack和ContextMap。OGNL看到getText(key)時(shí),它會(huì)在ValueStack中從上向上反射每一個(gè)對(duì)象,如果哪一個(gè)對(duì)象最先具有這個(gè)方法,則OGNL就調(diào)用這個(gè)對(duì)象的getText(key)方法。
除了在JSP頁(yè)面中需要使用到國(guó)際化資源,我們?cè)?span lang="EN-US" xml:lang="EN-US">Action中也需要使用國(guó)際化資源。此時(shí),我們需要將我們的Action類繼承自ActionSupport類,它實(shí)現(xiàn)了專門用于操作國(guó)際化的接口TextProvider。ActionSupport還實(shí)現(xiàn)了其他非常有用的接口,我們?cè)谙旅鏁?huì)總結(jié)。此后,我們只需要調(diào)用getText()方法,即可獲得相應(yīng)的資源信息。我們的Action也可以繼承自DefaultTextProvider類,但它默認(rèn)情況下去搜索全局資源包,不會(huì)找Action的資源包。而ActionSUpport正如我們?cè)谏厦嫠f(shuō),以Action的資源包優(yōu)先級(jí)最高...。
我們知道我們可以為國(guó)際化資源指定參數(shù),比如“regNameError={0} is invalid.”。我們?cè)?span lang="EN-US" xml:lang="EN-US">JSP頁(yè)面中可以通過(guò)<s:param></s:param>標(biāo)簽來(lái)指定,如:
<s:text name=”regNameError”> <s:param></s:param> </s:text> |
或<s:text name=”getText('regNameError','xxx')”></s:text>。在Action中直接使用getText(“regNameError”,”xxx”)。
我們之所以能夠如此方便的使用國(guó)際化支持,JDK中的java.util.Locale為此做了很大的貢獻(xiàn)。目前我們使用國(guó)際化操作,無(wú)不基于java.util.Locale。因?yàn)?span lang="EN-US" xml:lang="EN-US">OGNL的強(qiáng)大,我們也可以在JSP頁(yè)面中使用java.util.Locale還記得嗎?在OGNL中調(diào)用XXX類的靜態(tài)方法或成員的方式,比如調(diào)用java.util.Locale的getCountry():<s:property value=”@java.util.Locale@getDefault()”/>。
二、表單與Action數(shù)據(jù)交互
相比Struts1,在Strut2中的一大變化是我們不需要ActionForm了。我們?cè)谑褂?span lang="EN-US" xml:lang="EN-US">Struts1時(shí),為了操作表單數(shù)據(jù),我們需要額外定義一個(gè)繼承自ActionForm的FormBean。然后再將FormBean中的數(shù)據(jù)Copy到Bean中。
Struts2是如何實(shí)現(xiàn)對(duì)表單數(shù)據(jù)的操作呢?Struts2的ValueStack一直發(fā)輝著它的作用,ValueStack像是能完成Struts2的在所在操作,上面的國(guó)際化也是使用的ValueStack存儲(chǔ)的。在Struts2中操作表單數(shù)據(jù),我們需要在我們Action定義屬性。在Action添加的屬性可以是基本數(shù)據(jù)類型也可以是復(fù)合類型。
進(jìn)行表單與Action數(shù)據(jù)交互時(shí),我們的Action類無(wú)需實(shí)現(xiàn)任何接口或繼承自任何類。但是,我們必須在struts.xml中使用定義在struts-default.xml文件中的defaultStack攔截器堆棧。使用defaultStack我們必須在package中添加extends="struts-default"屬性。如果在我們的Action中沒(méi)有使用任何攔截器,defaultStack默認(rèn)被使用。如果有使用任何其他攔截器,我們必須手動(dòng)加入defaultStack攔截器堆棧。
Struts2正是使用在defaultStack中的params攔截器,來(lái)為我們的Action設(shè)置屬性值。如何使用基本類型屬性和復(fù)合類型屬性與JSP頁(yè)面交互呢?比如在我們的RegUserAction中有一個(gè)User屬性和一個(gè)字符串型的password2屬性。那么我們?cè)?span lang="EN-US" xml:lang="EN-US">JSP頁(yè)面中應(yīng)該這樣使用:
<s:form action=”RegUserAction”> <s:textfield name=”user.name”/> <s:textfield name=”user.password”/> <s:textfield name=”user.email”/> <s:textfield name=”password2”/> <s:submit value=”注冊(cè)”></s:submit> </s:form> |
點(diǎn)擊注冊(cè)按鈕后,Struts2正是使用params攔截器將數(shù)據(jù)設(shè)置到RegUserAction的屬性中。
因?yàn)檫@些表單字段數(shù)據(jù)是被保存在ValueStack中,所以我們?cè)?span lang="EN-US" xml:lang="EN-US">JSP頁(yè)面我們可以使用EL表達(dá)試,如:${user.name},也可以使用OGNL表達(dá)式,如:<s:property value=”user.name”/>來(lái)獲取數(shù)據(jù)。
除此之外,我們可以讓Action實(shí)現(xiàn)ModelDriven接口,并將User做為它的泛型參數(shù)。如果被ModelDriven接管的實(shí)體類型中有與我們的Action屬性相同的,ModelDriven的優(yōu)先級(jí)高。Struts2會(huì)設(shè)置ModelDriven接管的實(shí)體類型的是屬性,而忽略Action的同名屬性。但這并不會(huì)引起錯(cuò)誤,因?yàn)槲覀兊臄?shù)據(jù)全部放在ValueStack中,使用OGNL可以正確獲取。我們不推薦使用ModelDriven。
三、表單校驗(yàn)
表單校驗(yàn)在Struts2中實(shí)現(xiàn)比較簡(jiǎn)單,表單數(shù)據(jù)的校驗(yàn)分為前臺(tái)校驗(yàn)和后臺(tái)校驗(yàn)。同樣我們需要開啟defaultStack攔截器堆棧,首先我們來(lái)看看后臺(tái)校驗(yàn)。
后臺(tái)校驗(yàn),我們的Action可以繼承ValidationAwareSupport類和實(shí)現(xiàn)Validateable接口。因?yàn)槲覀兺瑫r(shí)需要在類中使用到國(guó)際化表單校驗(yàn),所以我們可以直接繼承ActionSupport類。Action類需要實(shí)現(xiàn)validate方法。
在validate方法中進(jìn)行Action的屬性校驗(yàn),并且我們可以調(diào)用ActionSupport類的addActionError(String)方法,添加錯(cuò)誤信息。我們可以在這里使用國(guó)際化支持,而在JSP頁(yè)面中需要使用<s:fieldError>取出所有錯(cuò)誤信息,或者指定字段名而取出某個(gè)字段的錯(cuò)誤信息。
但有一個(gè)問(wèn)題,一個(gè)Action類可以有多個(gè)方法分別用于處理不同的請(qǐng)求。Struts2每當(dāng)調(diào)用其中一個(gè)方法時(shí)都會(huì)進(jìn)行表單校驗(yàn),這沒(méi)必要??!所以我們?cè)诓恍枰M(jìn)行表單校驗(yàn)的方法上添加“@SkipValiation”注解,這樣就會(huì)被Struts2過(guò)濾掉。
我們也可以添加”ActionClassName-validation.xml”配置文件,來(lái)為指定名稱的Action(ActionClassName)添加表單校驗(yàn)。具體的配置可以參看struts2包中所帶的例子程序。我們也可以使用“ActionClassName-actionname-validation.xml”來(lái)為Action類中的某個(gè)具體方法指定表單校驗(yàn)。
前臺(tái)校驗(yàn),前臺(tái)校驗(yàn)的好處不再說(shuō)明了。前提我們以配置文件的方式為Action指定的表單校驗(yàn),那么在JSP頁(yè)面中,我們可以直接引用配置文件中的數(shù)據(jù),實(shí)現(xiàn)前臺(tái)校驗(yàn)。Struts2中的struts-tags為我們提供的表單標(biāo)簽中可以引用配置文件中對(duì)應(yīng)的校驗(yàn)數(shù)據(jù)。在我們?cè)L問(wèn)到某個(gè)JSP頁(yè)面時(shí),Struts2的標(biāo)簽會(huì)為我們自動(dòng)生成相應(yīng)的JavaScript代碼,但Struts2的表單前臺(tái)校驗(yàn)的這種功能還不夠強(qiáng)大。在此就不多做總結(jié)了。
老張講得比較細(xì)致,我也僅僅是泛泛而總結(jié)。按照正常的進(jìn)程,我們明天還有一天的Struts2課程,但由于時(shí)間不夠,老張決定哪天同學(xué)們休息時(shí)再為我們補(bǔ)一天,太好了!
posted @ 2010-02-23 23:39 長(zhǎng)城 閱讀(542) | 評(píng)論 (0) | 編輯 收藏