2008-05-11

Gwt-Ext学习笔记之进级篇

关键字: gwt ext google web toolkit cypal studio

 

Gwt-Ext学习笔记之进级篇

一、 定义服务

GWT过程调用大部分在两个类进行。在服务器端,定义一个 RemoteServiceServlet子类 RegisterActionImpl.java(远程服务实现类)。在这个类中,将操作数据库并将值返回给客户机。在客户端,定义一个实现 AsyncCallback接口的类 Register.java(客户端实现类),在这个类中,定义服务器操作完成时客户机页面如何处理数据(或异常)。除了这两个类之外,必须编写一些绑定代码使 GWT-Ext 可以将客户端类和服务器端类绑定在一起 , 绑定代码包含 RegisterAction.java(远程接口)和 RegisterActionAsync.java(远程异步接口)两个不同的接口外加一些客户端代码以及一两个设置。

a.       gwtext项目上点击右键,选择 New—Other—Remote Service,创建名为 RegisterAction的远程服务接口。

b.      PostgreSQL数据库的 JDBC postgresql-8.2-505.jdbc3.jar加入到项目中(其他数据库,加入相应的 JDBC包)。

c.       远程服务的实现类,在 RegisterActionImpl.java中加入如下代码:

 

/**
 * @author 七月天
 *
 */
public class RegisterActionImpl extends RemoteServiceServlet implements RegisterAction {

	private static final long serialVersionUID = 1L;

	public void saveData(Map formData) {
		Connection conn=null;
		try {
			Class.forName("org.postgresql.Driver");
			String connString="jdbc:postgresql://127.0.0.1:5432/gwtext";
			conn=DriverManager.getConnection(connString,"julycn","julycn");
			StringBuffer sqlQuery=new StringBuffer("insert into person (username,password,email,phone) ");
			sqlQuery.append("values(?,?,?,?)");
			PreparedStatement stmt=conn.prepareStatement(sqlQuery.toString());
			stmt.setString(1, URLDecoder.decode(formData.get("username").toString(),"UTF-8"));
			stmt.setString(2, URLDecoder.decode(formData.get("password").toString(),"UTF-8"));
			stmt.setString(3, URLDecoder.decode(formData.get("email").toString(),"UTF-8"));
			stmt.setString(4, URLDecoder.decode(formData.get("phone").toString(),"UTF-8"));
			stmt.execute();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			if(conn!=null){
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
}
 

d.      GWT-Ext远程服务的要求很简单,它必须扩展 RemoteServiceServlet并实现一个接口。

二、 绑定代码

a.       要使新程序可用于客户端应用程序,必须定义两个接口。

b.      定义一个远程接口类 RegisterAction.java,代码如下

/**
 * @author 七月天
 *
 */
public interface RegisterAction extends RemoteService {

	public static final String SERVICE_URI = "/RegisterAction";

	public static class Util {

		public static RegisterActionAsync getInstance() {

			RegisterActionAsync instance = (RegisterActionAsync) GWT
					.create(RegisterAction.class);
			ServiceDefTarget target = (ServiceDefTarget) instance;
			target.setServiceEntryPoint(GWT.getModuleBaseURL() + SERVICE_URI);
			return instance;
		}
	}

	public void saveData(Map formData);
}
 

c.       在这里完成的所有操作是获得用于实际的具体类中方法的同一个签名。这里的主要限制是接口必须扩展 com.google.gwt.user.client.rpc.RemoteService;。此外,参数和返回值必须属于 GWT 可以序列化的类型 (见备注 )

d.      定义远程异步接口 RegisterActionAsync.java ,代码如下:

/**
 * @author 七月天
 *
 */
public interface RegisterActionAsync {

	public void saveData(Map formData, AsyncCallback callback);
}
 

e.      远程异步类的服务接口是从上面描述的远程服务类中派生出来的。两个类必须位于同一个包中,并且该包必须对 GWT-EXT 客户机代码可见。远程异步类中的类名必须是远程服务接口的名称且末尾附加字符串 Async。对于远程服务接口中的每个方法,远程异步类必须有一个返回类型更改为 void 的匹配方法和一个 AsyncCallback 类型的附加参数。客户端代码将使用 AsyncCallback 作用于服务器响应上。

f.        注册服务器代码,将下面的一行加入到 Register.gwt.xml

<servlet class="com.gwtext.julycn.server.RegisterActionImpl" path="/RegisterAction" />
 

三、 执行客户端调用

a.       完成服务器端操作以后,现在应该让客户机执行过程调用了。在这里基本的想法是慎重地告诉 GWT 系统正在调用的是哪个远程服务。然后将 AsyncCallback 对象发送出去;最后, GWT 将其送回,您可对结果进行操作。修改模型文件 Register.java,代码如下:

 

/**
 * @author 七月天
 *
 */
public class Register implements EntryPoint,AsyncCallback {
	public void onModuleLoad() {
		createComponents();
	}

	private void createComponents() {
		final FormPanel frm = new FormPanel();
		frm.setDraggable(true);
		frm.setWidth(300);
		frm.setTitle("用户注册");
		frm.setPaddings(25);

		TextField txtUsername = new TextField("用户名", "username");
		TextField txtPassword = new TextField("密码", "password");
		TextField txtEmail = new TextField("邮箱", "email");
		TextField txtPhone = new TextField("电话", "phone");

		txtUsername.setRegex("^[a-zA-Z]*$");
		txtUsername.setRegexText("用户名必须为字母!");
		txtUsername.setAllowBlank(false);

		txtPassword.setPassword(true);
		txtPassword.setRegex("^[a-zA-Z]*$");
		txtPassword.setRegexText("密码必须为字母!");
		txtPassword.setAllowBlank(false);

		txtEmail.setVtype(VType.EMAIL);
		txtEmail.setVtypeText("请输入合法的邮箱地址!");
		txtEmail.setAllowBlank(false);

		txtPhone.setRegex("^\\d*$");
		txtPhone.setRegexText("电话必须为数字!");
		txtPhone.setAllowBlank(false);

		frm.add(txtUsername);
		frm.add(txtPassword);
		frm.add(txtEmail);
		frm.add(txtPhone);

		Panel buttonPanel = new Panel();
		buttonPanel.setLayout(new HorizontalLayout(10));

		final AsyncCallback callback=this;
		
		Button btnSave = new Button("保存");
		btnSave.addListener(new ButtonListenerAdapter() {
			public void onClick(Button button, EventObject e) {
				if (frm.getForm().isValid()) {
					RegisterActionAsync action=RegisterAction.Util.getInstance();
					Map formData=getFormDataAsMap(frm.getForm());
					action.saveData(formData, callback);
				} else {
					MessageBox.alert("错误","请验证输入的信息是否正确!");
				}
			}
		});

		Button btnClear = new Button("取消");
		btnClear.addListener(new ButtonListenerAdapter() {
			public void onClick(Button button, EventObject e) {
				MessageBox.alert("取消", "注册信息保存失败!");
			}
		});

		buttonPanel.add(btnSave);
		buttonPanel.add(btnClear);

		frm.add(buttonPanel);

		RootPanel.get().add(frm);
	}
	
	public Map getFormDataAsMap(Form form){
		
		String formValues=form.getValues();
		Map formData=new HashMap();
		String[] nameValuePairs=formValues.split("&");
		
		for(int i=0;i<nameValuePairs.length;++i){
			String[] oneItem=nameValuePairs[i].split("=");
			formData.put(oneItem[0], oneItem[1]);
		}
		
		return formData;
	}

	public void onFailure(Throwable caught) {
		MessageBox.alert("失败","数据保存失败!");
	}

	public void onSuccess(Object result) {
		MessageBox.alert("成功","数据保存成功!");
	}
}
 

b.      AsyncCallback 接口定义了两个方法: onSuccess(Object result) onFailure(Throwable caught)。必须定义一个可以实现这两个方法的类。当执行远程调用时,模型类的实例并将其传递给异步服务方法。最后,服务器端资源完成,然后调用代码中两个方法之一。成功方法的参数是接口和实现中的调用的返回值。

c.       运行一下,看看效果吧! ^o^

备注:

怎样的字段才是可序列化字段?首先,该字段可属于一个实现了 com.google.gwt.user.client.rpc.IsSerializable 的类型,或者具有一个实现了 IsSerializable 的超类。或者,该字段可以是基本类型之一,其中包括 Java 原语,所有原语包装类, Date String 。序列化类型的数组或集合也是序列化的。但是,如果要将一个 Collection List 序列化, GWT 希望您用一个指定实际类型的 Javadoc 注释对其评注,以便编译器可以使其最优化。

评论
liutianhao 2008-06-30
加入在基础篇中,我点击保存,保存成功后要跳转到中级篇中的显示页面该写哪些代码啊???
cavenaghi 2008-05-30
对于Java程序员,要学到,要了解到知识真的太多了,数据库、JS……

似乎更多的人喜欢以黑洞的方式去触摸他们,不想去了解其内在,而是使用相关的一些框架。其实各有利弊,框架仅仅可以作为参考,如果应用到项目中,风险还是比较大的。

希望大家,真正切实的去了解数据库、JS!

(以上言论不求赞同)
bernieyoo 2008-05-29
julycn 写道
bernieyoo 写道
我完全按楼主方式做了,数据可以正确保存。但当我把数据库关掉后再执行,无法抛出异常,仍然提示“保存成功”。

不知道是什么原因呢?

数据库是否真正关掉,最好确认一下数据是否保存。


这个可以确定。后台的trace是可以看到错误内容的,但页面提示成功。
但这只是在托管模式下会这样。Deploy到Tomcat后就可以正常报错了。
julycn 2008-05-27
bernieyoo 写道
我完全按楼主方式做了,数据可以正确保存。但当我把数据库关掉后再执行,无法抛出异常,仍然提示“保存成功”。

不知道是什么原因呢?

数据库是否真正关掉,最好确认一下数据是否保存。
bernieyoo 2008-05-27
我完全按楼主方式做了,数据可以正确保存。但当我把数据库关掉后再执行,无法抛出异常,仍然提示“保存成功”。

不知道是什么原因呢?
julycn 2008-05-18
zfswff 写道
这个东西要想做好,问题多多啊

如何在TOMCAT中部署还是个大问题啊


用ant编译好之后,直接copy到tomcat的webapps目录下就可以了
stworthy 2008-05-17
直接写JS是最彻底的,我倒觉得写JS比写GWT这样的代码更清晰。
crabboy 2008-05-17
还是觉得用javascript直接
zfswff 2008-05-16
怎么越来越感觉不如直接写JAVASCRIPT来的直接啊
zfswff 2008-05-16
这个东西要想做好,问题多多啊

如何在TOMCAT中部署还是个大问题啊
zfswff 2008-05-16
昨天的评论今天怎么找不到了呢
julycn 2008-05-11

补一张效果图,接上文

发表评论

提醒: 该博客已发表在公共论坛,博客所有留言会成为论坛回贴,留言请注意遵守论坛发贴规则

您还没有登录,请登录后发表评论

julycn
搜索本博客
我的相册
0a46256d-c842-3a98-84ca-5ee90d4e18ae-thumb
untitled.JPG
共 12 张
存档
最新评论