[Java] GWT with JSON

博客首页 » Java GWT with JSON

发布于 23 Dec 2014 15:45
标签 blog
GWT是一个优秀的Toolkit,一方面支持Client的Java->Javascript的编译优化,另一方面支持Client与Server间的RPC。只是这个RPC协议是Google专有的,并不通用。我们用JSON重新实现一遍这个RPC的功能。

Demo的基本结构

首先,使用GWT的Eclipse插件生成一个Demo。
它有两部分,一部分是client,一部分是server,还有一个共享shared部分。

  • shared部分有一些公用的代码,可以被client和server调用到
  • client有一个EntryPoint的Java程序以及GreetingService、GreetingServiceAsync的接口。
    • EntryPoint的Java程序,表达界面操作,用GWT的Java-Javascript编译,生成一个画面,有user的name输入框和一个提交按钮。
    • GreetingService与GreetingServiceAsync是一对一一对应的表达服务的接口
    • 当按钮被按下时,把user的name用GreetingServiceAsync发送出去。
  • server是一个实现了GreetingService接口的Servlet
    • 当收到GreetingService接口的调用时, 就会返回相应的结果
  • 从client的GreetingServiceAsync的调用,到server的GreetingService的调用,其间的数据封装和转化就被GWT封装了

我们的修改,就是基于这个基础。所以我们需要:

  • client发送信息时
    • 重写一个GreetingServiceAsync的实现
      • 用gwt json来组合json成为String。
      • 用RequestBuilder来发送request。
      • 用String来接受结果
      • 用JsonParser来解析结果String
    • 调用新的GreetingServiceAsync(因为接口略有不同)
  • server上接受GreeringService的调用
    • 用org.json解析String
    • 用org.json封装返回的String
GreetingServiceAsync

我们重用所有的接口,这样GWT清晰的结构以及与GWT的兼容性都不受影响。
我们可以看到GWT.create(GreetingService.class)的简洁代码被我们替换成了手动合成json,使用RequestBuilder发送的这两部分代码。
这里为了阐释原理,这里使用两种方法实现,一种是json的这个包。稍后我们还要继续讲解AutoBean。

    /**
     * Create a remote service proxy to talk to the server-side Greeting service.
     */
    private final GreetingServiceAsync greetingService = new GreetingServiceAsync() {
        @Override
        public void greetServer(String name, final AsyncCallback<String> callback)
                throws IllegalArgumentException {
            JSONObject inputs = new JSONObject();
            inputs.put("name", new JSONString(name));
 
            RequestBuilder builder = 
                    new RequestBuilder(RequestBuilder.POST, 
                    GWT.getModuleBaseURL()+ "greetJson"
                    );
 
            try {
                builder.sendRequest(inputs.toString(), new RequestCallback(){
                    @Override
                    public void onResponseReceived(Request request,
                            Response response) {
                        JSONValue rst = JSONParser.parseStrict(response.getText());
                        callback.onSuccess(response.getText());
                    }
                    @Override
                    public void onError(Request request, Throwable exception) {
                        callback.onFailure(exception);
                    }});
            } catch (RequestException exception) {
                callback.onFailure(exception);
            }
        }}; 
    /*
    private final GreetingServiceAsync greetingService = GWT
            .create(GreetingService.class);
    */
直接发送请求的方法实现
    JSONObject inputs = new JSONObject();
    inputs.put("name", new JSONString(nameField.getText()));
 
    RequestBuilder builder = 
            new RequestBuilder(RequestBuilder.POST, 
            GWT.getModuleBaseURL()+ "greetJson"
            //"http://localhost/alts/gwtest/php/gwtest.ajax.php"
            );
    try {
        builder.sendRequest(inputs.toString(), new RequestCallback(){
            @Override
            public void onResponseReceived(Request request,
                    Response response) {
                dialogBox.setText("Remote Procedure Call");
                serverResponseLabel
                        .removeStyleName("serverResponseLabelError");
 
                //serverResponseLabel.setHTML(result);
                JSONValue result = JSONParser.parseStrict(response.getText());
                JSONValue resultVal = result.isObject().get("result");
                String name = resultVal.isString().stringValue();
                serverResponseLabel.setHTML(name);
                dialogBox.center();
                closeButton.setFocus(true);
            }
            @Override
            public void onError(Request request, Throwable exception) {
                serverResponseLabel.setHTML(exception.toString());
            }});
        serverResponseLabel.addStyleName("serverResponseLabelError");
        serverResponseLabel.setHTML("request sent");
    } catch (RequestException e) {
        serverResponseLabel.setHTML(e.toString());
        throw new RuntimeException(e);
    }
使用与GWT相同的interface发送请求

原来的代码

    greetingService.greetServer(textToServer,
            new AsyncCallback<String>() {
                public void onFailure(Throwable caught) {
                    // Show the RPC error message to the user
                    dialogBox
                            .setText("Remote Procedure Call - Failure");
                    serverResponseLabel
                            .addStyleName("serverResponseLabelError");
                    serverResponseLabel.setHTML(SERVER_ERROR);
                    dialogBox.center();
                    closeButton.setFocus(true);
                }
 
                public void onSuccess(String result) {
                    dialogBox.setText("Remote Procedure Call");
                    serverResponseLabel
                            .removeStyleName("serverResponseLabelError");
 
                    serverResponseLabel.setHTML(result);
                    dialogBox.center();
                    closeButton.setFocus(true);
                }
            });

修改后的代码

    greetingService.greetServer(textToServer,
            new AsyncCallback<String>() {
                public void onFailure(Throwable caught) {
                    // Show the RPC error message to the user
                    dialogBox
                            .setText("Remote Procedure Call - Failure");
                    serverResponseLabel
                            .addStyleName("serverResponseLabelError");
                    serverResponseLabel.setHTML(SERVER_ERROR);
                    dialogBox.center();
                    closeButton.setFocus(true);
                }
 
                public void onSuccess(String result) {
                    dialogBox.setText("Remote Procedure Call");
                    serverResponseLabel
                            .removeStyleName("serverResponseLabelError");
 
                    JSONValue resultParse = JSONParser.parseStrict(result);
                    JSONValue resultVal = resultParse.isObject().get("result");
                    String name = resultVal.isString().stringValue();
                    serverResponseLabel.setHTML(name);
 
                    dialogBox.center();
                    closeButton.setFocus(true);
                }
            });

可以看到,我们增加了JSON解析的部分。
server端

接着是server端

package com.fj.gwtest.server;
 
import java.io.IOException;
 
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.commons.io.IOUtils;
import org.json.*;
 
import com.fj.gwtest.client.GreetingService;
 
public class GreetingJsonServiceImpl extends HttpServlet implements GreetingService {
    private static final long serialVersionUID = 1L;
 
    @Override
    protected 
     void doGet(HttpServletRequest req, HttpServletResponse resp) { 
        try {
            resp.getWriter().print(greetServer(req.getQueryString()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
 
    @Override
    protected 
     void doPost(HttpServletRequest req, HttpServletResponse resp) { 
        try {
            resp.getWriter().print(greetServer(IOUtils.toString(req.getReader())));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
 
    @Override
    public String greetServer(String inputStr) throws IllegalArgumentException {
        try {
            System.out.println("Received payLoad");
            JSONObject inputs = (JSONObject)new JSONTokener(inputStr).nextValue();
            String name = inputs.getString("name");
            String result = "{\"result\":\"" + escapeJsonHtml(name) + "\"}"; //" + escapeJson(name) + "
            return result;
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }
 
    /**
     * Escape an html string. Escaping data received from the client helps to
     * prevent cross-site script vulnerabilities.
     * 
     * @param html the html string to escape
     * @return the escaped string
     */
    private String escapeJsonHtml(String html) {
        if (html == null) {
            return null;
        }
        return html.replaceAll("&", "&amp;").replaceAll("<", "&lt;")
                .replaceAll(">", "&gt;")
                .replaceAll("\"", "&quot;");
    }
 
    private String escapeJson(String str) {
        if (str == null) {
            return null;
        }
        return str.replaceAll("\"", "\\\"");
    }
}
后话

我们还有几个可以改进的地方

  • 可以用json对于object, method进行封装,以完成更加类似与rpc的行为,并且传递复杂对象。
  • 可以用autobean封装/解析对象,完成自动化
  • 可以用JSONP代替JSON,实现跨域的访问
  • 可以用JSP+Component代替Servlet,实现动态开发测试

本页面的文字允许在知识共享 署名-相同方式共享 3.0协议和GNU自由文档许可证下修改和再使用,仅有一个特殊要求,请用链接方式注明文章引用出处及作者。请协助维护作者合法权益。


系列文章

文章列表

  • Java GWT with JSON

这篇文章对你有帮助吗,投个票吧?

rating: 0+x

留下你的评论

Add a New Comment
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License