posts - 78, comments - 34, trackbacks - 0, articles - 1
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

     摘要: 前两篇日志我已经总结了本地数据存储的前两种:文件和配置项。还剩下最后一种数据库存储——SQLite。   一、SQLite简介   在Android平台上,集成了一个嵌入式关系型数据库—SQLite,SQLite3支持 NULL、INTEGER、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然它支持的类型虽然只有五种,但实际上sqli...  阅读全文

posted @ 2010-03-01 22:58 長城 阅读(5802) | 评论 (5)编辑 收藏

     摘要:        在此之前的学习内容是数据存储之一文件存储。在本地存储中常用的有,文件、配置文件、数据库。前面的学习主要是针对本地文件的。我认为可以把SharedPreferences看做是配置文件,虽然它也是采用XML格式存储的。          比如我们使用的桌...  阅读全文

posted @ 2010-03-01 15:01 長城 阅读(2434) | 评论 (0)编辑 收藏

     摘要:        今日继续学习Android中使用Pull的XML解析技术实现对XML文件的解析和创建。由于明天休息,时间比较充裕,所以我也将昨天未总结的SAX解析技术在此做个总结。   一、SAX解析技术        Sax使用的是事件驱动的流式解析技术。事件驱...  阅读全文

posted @ 2010-03-01 12:01 長城 阅读(2940) | 评论 (0)编辑 收藏

     摘要:        今日重点内容是Adnroid的数据存储和访问。Android的数据存储有五种:文件 SharedPreferences、SQLite数据库、内容提供者(Content provider)、网络。今天老黎讲解Android的单元测试、文件存储和访问以及解析XML文件。   一、Android的单元测试 &nb...  阅读全文

posted @ 2010-02-27 21:31 長城 阅读(4775) | 评论 (4)编辑 收藏

 一、创建 Android工程

Project name:SendMessage

BuildTarget:Android2.1

Application name:发送短信

Package name:com.changcheng.Activity

Create Activity:SendMessage

Min SDK Version:7


二、编辑工程

1.编辑strings.xml文件内容为:

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

<resources>

<string name="hello">请输入手机号码:</string>

<string name="app_name">发送短信</string>

<string name="content">请输入信息内容:</string>

<string name="send">发送</string>

</resources>


2.编辑main.xml文件内容为:

<?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">

<!-- 请输入手机号码标签 -->

<TextView android:layout_width="fill_parent"

android:layout_height="wrap_content" android:text="@string/hello" />

<!-- 手机号码编辑框 -->

<EditText android:layout_width="fill_parent"

android:layout_height="wrap_content" android:id="@+id/mobile" />

<!-- 请输入信息内容标签 -->

<TextView android:layout_width="fill_parent"

android:layout_height="wrap_content" android:text="@string/content" />

<!-- 信息内容编辑框 -->

<EditText android:layout_width="fill_parent"

android:layout_height="wrap_content" android:minLines="3"

android:id="@+id/message" />

<!-- 发送按钮 -->

<Button android:layout_width="wrap_content"

android:layout_height="wrap_content" android:text="@string/send"

android:id="@+id/send"/>

</LinearLayout>

注意,我们在电话号码输入框和拨打电话按钮中添加了android:id属性。如电话号码输入框的android:id=”@+id/mobile”@代码R.java+id代码添加id静态内部类,mobile代表向id类中添加一个常量成员。ADT将自动为我们生成常量值。

android:minLines设置信息内容编辑框的最小行数。


3.编辑Call.java内容:

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);

// 根据ID获取按钮

Button button = (Button) this.findViewById(R.id.send);

// 注册按钮被单击事件

button.setOnClickListener(new OnClickListener() {


@Override

public void onClick(View v) {

// 根据ID获取手机号码编辑框

EditText mobileText = (EditText) findViewById(R.id.mobile);

// 获取手机号码

String mobile = mobileText.getText().toString();

// 根据ID获取信息内容编辑框

EditText messageText = (EditText) findViewById(R.id.message);

// 获取信息内容

String message = messageText.getText().toString();

// 移动运营商允许每次发送的字节数据有限,我们可以使用Android给我们提供 的短信工具。

if (message != null) {

SmsManager sms = SmsManager.getDefault();

// 如果短信没有超过限制长度,则返回一个长度的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:接收方的手机号码

scAddress:发送方的手机号码

text:信息内容

sentIntent:发送是否成功的回执,以后会详细介绍。

DeliveryIntent:接收是否成功的回执,以后会详细介绍。


4.编辑AndroidManifest.xml内容:

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

<!-- 注册发送短信的权限 -->

<uses-permission android:name="android.permission.SEND_SMS" />

</manifest>

注册发送短信的权限,如果没有注册这个,将使用不了系统的发送短信功能。以后在我们的应用程序开发中,有使用到系统功能的必须在这个文件中进行注册。我们可以查看Android的帮助手册都有哪些功能。(.../android-sdk-windows/docs/reference/android/Manifest.permission.html


三、启动模拟器

我们给谁发短信?我们可以启动两个模拟器。使用一个模拟器给另一个模拟器发信息。首先我们使用工具栏上的手机图标再添加一个Android2.1的模拟器,另记一个名称。


在启动两个模拟器之前,我们需要模拟器能“接收到信号”。如果我们的机器是联网的,启动模拟器后,主界面显示信号强度的旁边会有一个3G的字样,这说明模拟器已经能接收到信号了。如果我们的机器不能联网,那么将自己的IP地址、网关和DNS服务器都设置为相同的值,比如都设置为192.168.0.100。如果我们的机器是在局域网下,但没有联网,那么将自己的网关和DNS设置为路由的IP即可,一般情况下路由的IP192.168.0.1


OK,现在我们启动两个模拟器!


四、发送短信

我们启动模拟器后,可以看到模拟器窗口的标题栏上有555455556的字样。这是模拟器监听的端口即——127.0.0.15554


在工程上右键,Run As Android Application,选择其中的一个模拟器。比如选择了端口为5554的模拟器。OK,程序被加载到模拟器中了,会被自动运行。


我们在电话号码编辑框中输入5556(接收端模拟器的端口号),点击发送按钮!


OK,你看到效果了吗?5556主界面,显示信号强度的旁边显示收到新短信。


五、使用ADT插件发送短信给模拟器

如果机器太慢,无法启动两个模拟器,我们可以只启动一个模拟器。然后在菜单windows->show view->other->Android->Emulator Control打开Emulator Control面板。


Telephony Actions分组框中,Voice是呼叫,SMS是发送短信。Incoming number是模拟器的端口号,我们也可以使用这个功能给我们的模拟器拨打电话或发送短信。


posted @ 2010-02-27 00:20 長城 阅读(3500) | 评论 (0)编辑 收藏

 

一、创建 Android工程

Project name:Call

BuildTarget:Android2.1

Application name:拨打电话

Package name:com.changcheng.Activity

Create Activity:Call

Min SDK Version:7


二、编辑工程

1.编辑strings.xml文件内容为:

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

<resources>

<string name="hello">请输入 手机号码:</string>

<string name="app_name">拨打电话</string>

<string name="button_call">呼叫</string>

</resources>



2.编辑main.xml文件内容为:

<?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">

<!-- 标题标签 -->

<TextView android:layout_width="fill_parent"

android:layout_height="wrap_content" android:text="@string/hello" />

<!-- 电话号码输入框 -->

<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>

注意,我们在电话号码输入框和拨打电话按钮中添加了android:id属性。如电话号码输入框的android:id=”@+id/mobile”@代码R.java+id代码添加id静态内部类,mobile代表向id类中添加一个常量成员。ADT将自动为我们生成常量值。


3.编辑Call.java内容:

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);

// 根据ID获取按钮

Button button = (Button) this.findViewById(R.id.button_call);

// 为按钮添加被单击事件

button.setOnClickListener(new OnClickListener(){


@Override

public void onClick(View v) {

// 根据ID获取编辑框

EditText editText = (EditText) findViewById(R.id.mobile);

// 获取电话号码

String mobile = editText.getText().toString();

// 生成呼叫意图

Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+ mobile));

// 开始呼叫

startActivity(intent);

}

});

}

}



4.编辑AndroidManifest.xml内容:

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

<!-- 注册使用拨打电话功能的权限 -->

<uses-permission android:name="android.permission.CALL_PHONE"/>

</manifest>

注册使用拨打电话功能的权限,如果没有注册这个,将使用不了系统的拨打电话功能。以后在我们的应用程序开发中,有使用到系统功能的必须在这个文件中进行注册。我们可以查看Android的帮助手册都有哪些功能。(.../android-sdk-windows/docs/reference/android/Manifest.permission.html


三、启动模拟器

我们给谁打电话?我们可以启动两个模拟器。使用一个模拟器给另一个模拟器拨打。首先我们使用工具栏上的手机图标再添加一个Android2.1的模拟器,另记一个名称。


在启动两个模拟器之前,我们需要模拟器能“接收到信号”。如果我们的机器是联网的,启动模拟器后,主界面显示信号强度的旁边会有一个3G的字样,这说明模拟器已经能接收到信号了。如果我们的机器不能联网,那么将自己的IP地址、网关和DNS服务器都设置为相同的值,比如都设置为192.168.0.100。如果我们的机器是在局域网下,但没有联网,那么将自己的网关和DNS设置为路由的IP即可,一般情况下路由的IP192.168.0.1


OK,现在我们启动两个模拟器!


四、拨打电话

我们启动模拟器后,可以看到模拟器窗口的标题栏上有555455556的字样。这是模拟器监听的端口即——127.0.0.15554


在工程上右键盘,Run As Android Application,选择其中的一个模拟器。比如选择了端口为5554的模拟器。OK,程序被加载到模拟器中了,会被自动运行。


我们在电话号码编辑框中输入5556(接收端模拟器的端口号),点击呼叫按钮!


OK,你看到效果了吗?5554模拟器显示正在呼叫,5556模拟器有来电显示...


五、使用ADT插件呼叫模拟器

如果机器太慢,无法启动两个模拟器,我们可以只启动一个模拟器。然后在菜单windows->show view->other->Android->Emulator Control打开Emulator Control面板。


Telephony Actions分组框中,Voice是呼叫,SMS是发送短信。Incoming number是模拟器的端口号,我们也可以使用这个功能给我们的模拟器拨打电话或发送短信。

 

posted @ 2010-02-26 23:00 長城 阅读(3709) | 评论 (0)编辑 收藏

     摘要:   万众瞩目,Android终于开课了。本课程有黎活明老师主讲,讲课细致而流畅。想做细他的课程总结,那我没时间和精力了。也是总结个框框,虽然是个框框,但如果看着我的日志跟着我做,也能做起Android开发。 今日的重点内容是,3G简介、Android简介、Android的开发环境搭建、HelloWorld程序、Android程序运行过程、拨打电话小程序、发送短信小程序。我们跳...  阅读全文

posted @ 2010-02-26 21:21 長城 阅读(5335) | 评论 (2)编辑 收藏

 我今天用Struts2Spring整合,但部署到Tomcat(tomcat-6.0.20)时,WabAppClassLoader却给我抛出了一个异常:ClassNotFindException:xxx.ActionServletActionServletStruts1中使用的Action控制器。但我使用的是Struts2啊!

我反复查看自己的配置文件和使用到的Jar包,没有任何问题。然后到网上搜索答案,出现这个问题的人还不少。有的是使用Strut1出现这个问题,那么他可能是没有导入Struts1的核心包导致的。至于使用Struts2也出现这个问题多少就有些奇怪了。

一些网友给出答案,是将Tomcat删除,然后安装一个新的Tomcat这样就可以解决问题。确实如此,我使用这个方法解决了问题。但为什么会出现这个问题呢?我最先想到的是Tomcat可能有缓存功能,于是我查看Tomcat的目录。发现它有一个temp目录和一个work目录,temp目录是做什么用的我不知道,work目录是为我们生成JSPclass文件。

问题就可能出现在这两个目录,所以以后遇见莫名其妙的问题可以删除这两个目录中的内容,然后再试一试。

posted @ 2010-02-25 23:58 長城 阅读(439) | 评论 (0)编辑 收藏

       Struts2第四天,正如预期Struts2的内容还没有讲完,还需要再加一天课。按照正常的授课方式,Struts2在四天内是可以讲完的,但这可能是老张最后一次讲Struts2,所以他要讲得细致些。

 

       今天的重点内容是Struts2的表单错误信息排版、Struts2中的FreeMark、和Struts2中的UI标签。老张计的比较细致,我做总结就不做的那么细致了。

 

一、Struts2的表单错误信息排版

       Struts2的表单错误信息排版是一个比较常见的问题,但网给所见到的解决方案似乎并不正统。老张给出了他的解决方法。

 

       通过之前的学习,我们知道Struts2中的大部分数据交互操作是由ValueStack来完成的。错误信息也是如此。我们在后台使用配置文件校验或硬编码校验,Struts2将错误信息存放在类型为MapfieldErrors对象中。

 

       我们可以在页面表单字段的后边添加此错误信息,比如在user.name表单字段后边添加<s:property value="fieldErrors['user.name'][0]"/>,这样错误信息可以显示在对应的字段后边。这是针对我们使用非struts2ui标签时(使用提htmlui标签)。但这里有一个问题,如果我的表单字段特别的多,难道我要手动为每个字段添加一个这样的错误信息,这多少有些麻烦,而且以后字段有什么变化还需要行动更改...

 

       Struts2在各方面都做的非常细致和人性化,Struts2UI标签等主要是使用FreeMark来实现的。Struts2使用FreeMar来实现模板和主题,那么我们回显表单数据和错误信息也可以使用FreeMark来实现。此时我们的表单需要使用struts-tags提供的标签来定义,然后我们修改它的ftl模板文件。

 

       下面我们看看一下应该如何修改ftl模板文件,我们以UI标签<s:textarea>为例。Struts2的模板文件存在哪?在Struts2的核心包中的template.xhtml中,textarea.ftl文件内容:

<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />

<#include "/${parameters.templateDir}/simple/textarea.ftl" />

<#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" />

      

       我们只需修改 controlheader.ftlcontrolfooter.ftl即可,难道我们需要修改Struts2核心包中的内容?当然不用,这一点Struts2已经为我们考虑到了。我们将这两个文件解压缩并放到WebRoot目录下的”template/xhtml”目录,必须是xhtml目录。看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会先到我们的WebRoot目录搜索相关ftl文件,如果没有才到自己的包中找。

 

       我们的目标,要使用Struts2UI标签并将错误信息显示在标签的旁边。所以我们修改这两个文件的内容为:

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的核心包中有一个default.properties配置文件,Struts2的默认配置都在这个文件中。有一些配置是开启的有一些配置是关闭的。我们要想打开被关闭的配置可以在struts.xml中,添加<constant name="配置项名" value="配置项值"></constant>元素。

 

       default.properties中有一个struts.freemarker.manager.classname=org.apache.struts2.views.freemarker.FreemarkerManager配置,Struts2是通过FreemarkerManager类来实现对Freemarker的操作的。

 

       通过查看源代码,我们知道通过调用FreemarkerManager类的buildTemplateModel方法生成一个model对象,然后将这个对象放在ValueStack中提供给Freemarker的引擎使用。model中都包含发哪些数据?Freemark的模板信息自然不用说,它还包含RequestApplicationResponse等这些在WEB应用中常用到的对象。具体我就不详细列出了,大家可以查看源代码。我们在上边两个模板文件中使用到的 parameters.name也是存储在model中的。

 

       在此特别提出一个被叫做UIBean的类型,UIBean就是对应Struts2UI标签的对象实体。比如标签有namethemeid等数据,这些都会被封装到UIBean中。Freemarker也正是使用这个东东给我们生成了相应该的页面文件。    

 

三、Struts2中的UI标签

       关于各UI标签的详细使用方式,在此就不做总结了。

 

       在实际开发中有一个重要的问题需要我们解决,比如有一个选择个人喜好的表单。我们需要通过一个Action的方法(likesUI)将喜好列表提供给页面,可以让用户选择。但在应用提交选择进行表单校验时,用户提交的数据不合法,我们需要重新返回到用户选择的界面。此时,我们需要调用 likesUI,获取列表将数据提供给用户选择的界面。

 

       我们可以在Action中添加”<result name="input" type="chain">likesUI</result>”,使其发生错误时直接跳转到likesUI,我们也需要在likesUI中添加一个 名称为inputresult标签,但这个标签的值不能为likesUI,否则会递归调用,直到缓存溢出。我们应将它的值指定为likesUI.jsp页面。但即使指定了这个页面,Struts2的内部实现方式也不会调用likesUI方法从,不会将数据传递给likesUI.jsp页面,而它直接跳转到likesUI.jsp页面。

 

       看来我们不能这么做,通过张老师对源代码的详细解析,我们只需要将likesUIAction中的likesUI的方法命名为input(),并只在likeUIAction中添加”<result name="input">/WEB-INF/pages/user/likesUI.jsp</result>“即可。为什么呢?

 

       在表单校验发生错误并使用 chain进行跳转时,会被chain拦截器给拦截了(ActionChainResult)。然后又会被拦截器validation给拦截了,它再进行表单校验进还是以前的数据,还是会出错然后它就直接跳转到我们指定的页面了。注意配置文件中的validation

<interceptor-ref name="validation">

       <param name="excludeMethods">input,back,cancel,browse</param>

</interceptor-ref>

它忽略请求为 input,back,cancel,browse请求路径。所以我们需要将我们的方法名定义为 input()

 

       我只是泛泛而结,如果想了解Struts2的更多细节请下载老张的视频看吧!

 

       最后送给大家一个Struts2开发用例参考模式图:

clip_image002
       1.用户申请注册,打开注册页面。

       2.用户提交注册申请,表单校验错误。

       3.表单校验错误不要跳转到regUser.jsp页面,而是应该跳转到RegUserUI这个Action方法。

       4.用户提交注册申请,表单校验通过。

       5.表单校验通过,调用RegUser这个Action方法进行注册。

       6.注册成功后,不要跳转到list.jsp页面。而是应该调用ListAction这个Action方法。

       7.ListAction获取所有用户信息后,跳转到list.jsp

 

       一定要记得老张还有一天的Struts2的课程,下一次课程的重点内容应该是Struts2的文件上传与下载,Struts2的防止表单重复提交,Struts2SpringAJAX整合,Struts2的插件。

 

       接下来的课程内容让我等的好久啊——Android!虽然听学习过的同学们说十分简单,但我还是迫不及待的想Android的一睹真容。我想很多人都是这样吧!那就关注我接下来6天课程的总结日志吧!

posted @ 2010-02-25 21:32 長城 阅读(573) | 评论 (0)编辑 收藏

       Struts2第三天。如果老张他喜欢头发,他肯定会把头上的头发有多少根,一根一根的数出来。他搞的太细了!

 

       今天的重点内容是国际化、表单与Action数据交互、表单校验,不多说了开始总结。

 

一、Struts2国际化

       在我们学习WEB基础的时候就讲到了国际化,Struts2中的国际化实现方式与我们之前所学习到的国际化相同。但是Struts2中对国际化做了强化支持!

 

       我们通过在struts.xml文件中加入”<constant name="struts.custom.i18n.resources" value="*.properties"></constant>”为指定全局国际化资源文件。Struts2会根据浏览器设置的语言信息运行对应的国际化文件,如果没找到就根据操作系统的语言查找指定的文件,还是没有,那就使用默认的。我们必须在struts.xml中使用定义在struts-default.xml文件中的defaultStack拦截器堆栈。使用defaultStack我们必须在package中添加extends="struts-default"属性。如果在我们的Action中没有使用任何拦截器,defaultStack默认被使用。如果有使用任何其他拦截器,我们必须手动加入defaultStack拦截器堆栈。Struts2将使用defaultStack拦截器堆栈中的i18n拦截器,为我们提供国际化支持。

 

       引入多个全局资源包的方法是在上面的value属性中添加以”,”分隔的多个资源文件。排在最后的资源包的优先级别最高(如果有重复的资源名称)。那如果有时我想在JSP页面中使用第一个资源包中的资源怎么办?Struts2为我们提供了一个标签“<s:i18n name="first.properties"></s:i18n>”,在标签体内使用到的国际化资源,全以first.properties为先。

 

       我们可以为每个Action指定一个资源包,资源包的名称与Action的名称相同。Struts2的国际化模块会先找与Action对应的资源包,如果没有就找它上一级的资源包,就这样逐级向上。如果直到类所在包的是后一层目录也没找到就使用全局资源。这有什么好处?我们可能会有多个Action使用同一个或多个相同的资源,难道我们要在每个Action对应的资源包里定义它吗?当然不需要,我们只需要把它定义在这几个Action的上级且同一目录即可。

 

       我们如何在JSP页面有使用国际化资源?Struts2tags为我们提供了“<s:text name=""></s:text>”标签,它是专门用来访问国际化资源的。除此之外我们也可以使用“<s:property value=”getText(key)”>”,这个getText()是哪来的?当然是ValueStack中的某个对象的方法喽!是类型为com.opensymphony.xwork2.DefaultTextProvider对象的。Struts2中使用OGNL操作ValueStackContextMapOGNL看到getText(key)时,它会在ValueStack中从上向上反射每一个对象,如果哪一个对象最先具有这个方法,则OGNL就调用这个对象的getText(key)方法。

 

       除了在JSP页面中需要使用到国际化资源,我们在Action中也需要使用国际化资源。此时,我们需要将我们的Action类继承自ActionSupport类,它实现了专门用于操作国际化的接口TextProviderActionSupport还实现了其他非常有用的接口,我们在下面会总结。此后,我们只需要调用getText()方法,即可获得相应的资源信息。我们的Action也可以继承自DefaultTextProvider类,但它默认情况下去搜索全局资源包,不会找Action的资源包。而ActionSUpport正如我们在上面所说,以Action的资源包优先级最高...

 

       我们知道我们可以为国际化资源指定参数,比如“regNameError={0} is invalid.”。我们在JSP页面中可以通过<s:param></s:param>标签来指定,如:

<s:text name=”regNameError”>

       <s:param></s:param>

</s:text>

<s:text name=”getText('regNameError','xxx')”></s:text>。在Action中直接使用getText(“regNameError”,”xxx”)

 

       我们之所以能够如此方便的使用国际化支持,JDK中的java.util.Locale为此做了很大的贡献。目前我们使用国际化操作,无不基于java.util.Locale。因为OGNL的强大,我们也可以在JSP页面中使用java.util.Locale还记得吗?在OGNL中调用XXX类的静态方法或成员的方式,比如调用java.util.LocalegetCountry()<s:property value=”@java.util.Locale@getDefault()”/>

 

二、表单与Action数据交互

       相比Struts1,在Strut2中的一大变化是我们不需要ActionForm了。我们在使用Struts1时,为了操作表单数据,我们需要额外定义一个继承自ActionFormFormBean。然后再将FormBean中的数据CopyBean中。

 

       Struts2是如何实现对表单数据的操作呢?Struts2ValueStack一直发辉着它的作用,ValueStack像是能完成Struts2的在所在操作,上面的国际化也是使用的ValueStack存储的。在Struts2中操作表单数据,我们需要在我们Action定义属性。在Action添加的属性可以是基本数据类型也可以是复合类型。

 

       进行表单与Action数据交互时,我们的Action类无需实现任何接口或继承自任何类。但是,我们必须在struts.xml中使用定义在struts-default.xml文件中的defaultStack拦截器堆栈。使用defaultStack我们必须在package中添加extends="struts-default"属性。如果在我们的Action中没有使用任何拦截器,defaultStack默认被使用。如果有使用任何其他拦截器,我们必须手动加入defaultStack拦截器堆栈。

 

       Struts2正是使用在defaultStack中的params拦截器,来为我们的Action设置属性值。如何使用基本类型属性和复合类型属性与JSP页面交互呢?比如在我们的RegUserAction中有一个User属性和一个字符串型的password2属性。那么我们在JSP页面中应该这样使用:

<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=”注册”></s:submit>

</s:form>

 

       点击注册按钮后,Struts2正是使用params拦截器将数据设置到RegUserAction的属性中。

 

       因为这些表单字段数据是被保存在ValueStack中,所以我们在JSP页面我们可以使用EL表达试,如:${user.name},也可以使用OGNL表达式,如:<s:property value=”user.name”/>来获取数据。

 

       除此之外,我们可以让Action实现ModelDriven接口,并将User做为它的泛型参数。如果被ModelDriven接管的实体类型中有与我们的Action属性相同的,ModelDriven的优先级高。Struts2会设置ModelDriven接管的实体类型的是属性,而忽略Action的同名属性。但这并不会引起错误,因为我们的数据全部放在ValueStack中,使用OGNL可以正确获取。我们不推荐使用ModelDriven

 

三、表单校验

       表单校验在Struts2中实现比较简单,表单数据的校验分为前台校验和后台校验。同样我们需要开启defaultStack拦截器堆栈,首先我们来看看后台校验。

 

       后台校验,我们的Action可以继承ValidationAwareSupport类和实现Validateable接口。因为我们同时需要在类中使用到国际化表单校验,所以我们可以直接继承ActionSupport类。Action类需要实现validate方法。

 

       validate方法中进行Action的属性校验,并且我们可以调用ActionSupport类的addActionError(String)方法,添加错误信息。我们可以在这里使用国际化支持,而在JSP页面中需要使用<s:fieldError>取出所有错误信息,或者指定字段名而取出某个字段的错误信息。

 

       但有一个问题,一个Action类可以有多个方法分别用于处理不同的请求。Struts2每当调用其中一个方法时都会进行表单校验,这没必要啊!所以我们在不需要进行表单校验的方法上添加“@SkipValiation”注解,这样就会被Struts2过滤掉。

 

       我们也可以添加”ActionClassName-validation.xml”配置文件,来为指定名称的Action(ActionClassName)添加表单校验。具体的配置可以参看struts2包中所带的例子程序。我们也可以使用“ActionClassName-actionname-validation.xml”来为Action类中的某个具体方法指定表单校验。

 

       前台校验,前台校验的好处不再说明了。前提我们以配置文件的方式为Action指定的表单校验,那么在JSP页面中,我们可以直接引用配置文件中的数据,实现前台校验。Struts2中的struts-tags为我们提供的表单标签中可以引用配置文件中对应的校验数据。在我们访问到某个JSP页面时,Struts2的标签会为我们自动生成相应的JavaScript代码,但Struts2的表单前台校验的这种功能还不够强大。在此就不多做总结了。

 

       老张讲得比较细致,我也仅仅是泛泛而总结。按照正常的进程,我们明天还有一天的Struts2课程,但由于时间不够,老张决定哪天同学们休息时再为我们补一天,太好了!

posted @ 2010-02-23 23:39 長城 阅读(530) | 评论 (0)编辑 收藏

仅列出标题
共8页: 上一页 1 2 3 4 5 6 7 8 下一页