转帖:http://www.javaeye.com/topic/191819
一、 定义服务
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中加入如下代码:
-
-
-
-
- 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();
- }
- }
- }
-
- }
- }
/**
* @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,代码如下
-
-
-
-
- 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);
- }
/**
* @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 ,代码如下:
-
-
-
-
- public interface RegisterActionAsync {
-
- public void saveData(Map formData, AsyncCallback callback);
- }
/**
* @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" />
<servlet class="com.gwtext.julycn.server.RegisterActionImpl" path="/RegisterAction" />
三、 执行客户端调用
a. 完成服务器端操作以后,现在应该让客户机执行过程调用了。在这里基本的想法是慎重地告诉 GWT 系统正在调用的是哪个远程服务。然后将 AsyncCallback 对象发送出去;最后, GWT 将其送回,您可对结果进行操作。修改模型文件 Register.java,代码如下:
-
-
-
-
- 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("成功","数据保存成功!");
- }
- }
/**
* @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 注释对其评注,以便编译器可以使其最优化。