GWT:多标签的简单聊天应用程序

时间:2014-06-23 07:55:29

标签: gwt server-push

抱歉我的问题太久了。我完全是GWT的新手,我的经验还很少。我想用GWT创建简单的聊天应用程序。

我在this使用 java + servlet + jsp 找到了一个简单的java聊天应用程序链接。我对它进行了修改并转换为GWT可压缩代码。 (我使用GAE http://gwt-chatting-test.appspot.com部署了它)。我相信我的代码可能有很多弱点和安全漏洞,但我处理它们的经验较少。(如果你找到了,请善意纠正我)

我想完整地描述我的代码。我使用了servlet 2.4,GWT 2.5,UI Binder和其他必需的库。

1)。登录页面

Index.ui.xml

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:d="urn:import:com.google.gwt.dom.client">
<ui:style>
    .important {
        font-weight: bold;
    }
    .lblUserName {
    margin-right: 3px;
    }
</ui:style>
<g:HTMLPanel>
    <center>
        <g:HorizontalPanel>
            <g:Label ui:field="lblUserName" text="User Name : " styleName="{style.lblUserName}"/><g:TextBox  height="15px" ui:field="txtUserName"/>
            <g:Button styleName="{style.important}" text="Login" ui:field="btnLogin" />
        </g:HorizontalPanel>
    </center>
</g:HTMLPanel>

Index.java

public class Index extends Composite {

interface IndexUiBinder extends UiBinder<Widget, Index> {}

private static IndexUiBinder uiBinder = GWT.create(IndexUiBinder.class);
@UiField Button btnLogin;
@UiField TextBox txtUserName;

private ChatServiceAsync chatService = GWT.create(ChatService.class);

public Index() {
    initWidget(uiBinder.createAndBindUi(this));
}

@UiHandler("btnLogin")
void onClick(ClickEvent e) {
    login();
}

@UiHandler("txtUserName")
void onKeyDown(KeyDownEvent event) {
    if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
        if (txtUserName.getText().trim().length() == 0) {
            Window.alert("Enter your name for chat-room !");
        }
        else {
            login();
        }
    }
}

private void login() {
    AsyncCallback<String> callback = new AsyncCallback<String>() {

        @Override
        public void onSuccess(String result) {
            RootPanel.get().clear();
            RootPanel.get().add(new Chat());
        }

        @Override
        public void onFailure(Throwable caught) {
            System.err.println(caught.getMessage());
        }
    };
    chatService.login(txtUserName.getText(), callback);
}
}

2)。用于聊天页面

Chat.ui.xml

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:style>
    .main {
    height: 420px;
    border: 1px solid silver;
    padding: 2px;
    width: 620px;
    margin-bottom: 5px;
    }
    .txtInputMsg {
    margin-right: 3px;
    width : 560px;
    height :25px;
    }

</ui:style>
<g:HTMLPanel>
    <center>
        <g:VerticalPanel>
            <g:ScrollPanel styleName="{style.main}"  height="420px" width="620px" ui:field="pnlMain">
                <g:VerticalPanel  ui:field="pnlMessage"/>
            </g:ScrollPanel>
            <g:HorizontalPanel ><g:TextBox styleName="{style.txtInputMsg}" ui:field="txtInputMsg"/><g:Button ui:field="btnLogout" text="Logout"/></g:HorizontalPanel>
        </g:VerticalPanel>
    </center>
</g:HTMLPanel>

Chat.java

public class Chat extends Composite {
public interface MessageTemlate extends SafeHtmlTemplates {
    @Template("<div class =\"{2}\"><div class = \"msgTitle\"> {0}</div><div class=\"msgDescription\">{1}</div></div>")
    SafeHtml getFormattedMessage(String name, SafeHtml message, String backgroundColor);

    @Template("<div class =\"loginInform\"><span class=\"userName\">{0}</span> has been joined to this conversation !</div>")
    SafeHtml notifyLoginUser(String userName);

    @Template("<div class =\"logoutInform\"><span class=\"userName\">{0}</span> has been left from this conversation !</div>")
    SafeHtml notifyLogoutUser(String userName);
}

private static ChatUiBinder uiBinder = GWT.create(ChatUiBinder.class);
@UiField TextBox txtInputMsg;
@UiField ScrollPanel pnlMain;
@UiField VerticalPanel pnlMessage;
@UiField Button btnLogout;

private static final XMLHttpRequest request = XMLHttpRequest.create();
private static final MessageTemlate TEMPLATES = GWT.create(MessageTemlate.class);
private ChatServiceAsync chatService = GWT.create(ChatService.class);
private String loginUser;
private Timer timer;

interface ChatUiBinder extends UiBinder<Widget, Chat> {}

public Chat() {
    initWidget(uiBinder.createAndBindUi(this));
    pnlMessage.getElement().setAttribute("style", "width:100%");
    initLoginUserName();
    request.open("post", URL.encode(GWT.getModuleBaseURL()
            + "chat.do?action=login&time='" + new Date().getTime() + ""));
    request.send(null);
}

@UiHandler("txtInputMsg")
void sendMessage(KeyDownEvent event) {
    if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
        if (txtInputMsg.getText().trim().length() > 0) {
            SafeHtml message = SafeHtmlUtils.fromTrustedString(txtInputMsg.getText());
            request.open("post", URL.encode(GWT.getModuleBaseURL()
                    + "chat.do?action=send&msg=" + message.asString() + "&time='" + new Date().getTime() + ""));
            txtInputMsg.setText("");
            pnlMessage.add(new HTML(TEMPLATES.getFormattedMessage(loginUser, message, "myMessage")));
            pnlMain.scrollToBottom();
            txtInputMsg.setFocus(true);
            request.send(null);
        }
    }
}

@UiHandler("btnLogout")
void logout(ClickEvent e) {
    boolean confirm = Window.confirm("Are you sure you want to logout now ?");
    if (confirm) {
        timer.cancel();
        request.open("post", URL.encode(GWT.getModuleBaseURL()
                + "chat.do?action=logout&time='" + new Date().getTime() + ""));
        request.send(null);
        AsyncCallback<String> callback = new AsyncCallback<String>() {

            @Override
            public void onSuccess(String result) {
                RootPanel.get().clear();
                RootPanel.get().add(new Index());

            }

            @Override
            public void onFailure(Throwable caught) {
                System.err.println(caught.getMessage());

            }
        };
        chatService.logOut(loginUser, callback);
    }
}

private void initChatListener() {
    timer = new Timer() {
        @Override
        public void run() {
            request.open("post", URL.encode(GWT.getModuleBaseURL()
                    + "chat.do?action=get&time='"
                    + new Date().getTime() + ""));
            request.send(null);
            request.setOnReadyStateChange(new ReadyStateChangeHandler() {

                @Override
                public void onReadyStateChange(XMLHttpRequest xhr) {
                    if (xhr.getReadyState() == 4) {
                        if (xhr.getStatus() == 200 && xhr.getResponseText().trim().length() > 1) {
                            HTML html = new HTML(xhr.getResponseText().trim());
                            JSONValue value = JSONParser.parseLenient(html.getText());
                            JSONWrapper json = new JSONWrapper(value);
                            for (int i = 0; i < json.getValue().isArray().size(); i++) {
                                String[] chatData = json.get(i).getValue().toString()
                                        .replaceAll("\"", "").split(":");
                                if (chatData.length >= 3) {
                                    if (chatData[2].equals("login")) {
                                        pnlMessage.add(new HTML(TEMPLATES.notifyLoginUser(chatData[0])));
                                    }
                                    else {
                                        pnlMessage.add(new HTML(TEMPLATES.notifyLogoutUser(chatData[0])));
                                    }
                                }
                                else {
                                    pnlMessage.add(new HTML(TEMPLATES.getFormattedMessage(chatData[0],
                                            SafeHtmlUtils.fromTrustedString(chatData[1]), "receivedMessage")
                                            .asString()));
                                }
                                pnlMain.scrollToBottom();
                            }
                        }
                    }

                }
            });
        }
    };
    timer.scheduleRepeating(1000);
}

private void initLoginUserName() {
    AsyncCallback<String> callback = new AsyncCallback<String>() {

        @Override
        public void onSuccess(String result) {
            loginUser = result;
            if (loginUser == null) {
                Window.alert("You need to login !");
                RootPanel.get().clear();
                RootPanel.get().add(new Index());
            }
            else {
                initChatListener();
            }
        }

        @Override
        public void onFailure(Throwable caught) {
            System.err.println(caught.getMessage());
        }
    };
    chatService.getUsername(callback);
}
}

3)。 RPC的服务和ServiceAsync

ChatService.java

@RemoteServiceRelativePath("chatService")
public interface ChatService extends RemoteService {
String login(String userName);
String getUsername();
String logOut(String username);
}

ChatServiceAsync.java

public interface ChatServiceAsync {
void login(String userName, AsyncCallback<String> callback);
void getUsername(AsyncCallback<String> callback);
void logOut(String username, AsyncCallback<String> callback);
}

4)。服务器端控制

ChatServiceImpl.java

@SuppressWarnings("serial")
public class ChatServiceImpl extends RemoteServiceServlet implements ChatService {

public String login(final String userName) {
    String newUserName = userName;
    HttpSession httpSession = getThreadLocalRequest().getSession();
    Map<String, List<String>> chat = ChatSupport.getChattingUsers();
    synchronized (chat) {
        // prevent userName conflict
        int i = 1;
        while (chat.containsKey(newUserName)) {
            ++i;
            newUserName = userName + "(" + i + ")";
        }
        chat.put(newUserName, new ArrayList<String>());
    }
    httpSession.setAttribute("UID", newUserName);
    return "LOGIN_SUCCESS";
}

public String logOut(String username) {
    // remove the mapping of user name
    ChatSupport.getChattingUsers().remove(username);
    getThreadLocalRequest().getSession().invalidate();
    return "LOGOUT_SUCCESS";
}

public String getUsername() {
    // check if there is a HTTP session setup.
    HttpSession httpSession = getThreadLocalRequest().getSession(false);
    if (httpSession == null) {
        return null;
    }
    // return the user name
    return (String) httpSession.getAttribute("UID");
}
}

ChatSupport.java

@SuppressWarnings("serial")
public class ChatSupport extends HttpServlet {
// message map, mapping user UID with a message list
private static Map<String, List<String>> users = new HashMap<String, List<String>>();

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    req.setCharacterEncoding("UTF-8");
    String action = req.getParameter("action");
    if ("login".equals(action)) {
        String userName = (String) req.getSession().getAttribute("UID");
        for (String key : users.keySet()) {
            if (!key.equals(userName)) {
                synchronized (users.get(key)) {
                    users.get(key).add(userName + "::login");
                }
            }
        }
    }
    else if ("logout".equals(action)) {
        String userName = (String) req.getSession().getAttribute("UID");
        for (String key : users.keySet()) {
            if (!key.equals(userName)) {
                synchronized (users.get(key)) {
                    users.get(key).add(userName + "::logout");
                }
            }
        }
    }
    // send message
    else if ("send".equals(action)) {
        // get param with UTF-8 enconding
        String msg = new String(req.getParameter("msg").getBytes("ISO-8859-1"), "UTF-8");
        String userName = (String) req.getSession().getAttribute("UID");
        for (String key : users.keySet()) {
            if (!key.equals(userName)) {
                synchronized (users.get(key)) {
                    // put message to any other user's msg list
                    users.get(key).add(userName + ":" + msg);
                }
            }
        }
    }
    else if ("get".equals(action)) { // get message
        String userName = (String) req.getSession().getAttribute("UID");
        if (userName == null) resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
        List<String> messages = users.get(userName);
        synchronized (messages) {
            if (messages.size() > 0) {
                // for UTF-8 chars
                resp.setCharacterEncoding("UTF-8");
                PrintWriter out = resp.getWriter();
                JSONArray result = new JSONArray();
                // add all msg to json array and clear list
                while (messages.size() > 0) {
                    result.add(messages.remove(0));
                }
                out.println(result);
                out.close();
            }
        }
    }
}
public static Map<String, List<String>> getChattingUsers() {
    return users;
}
}

5)。我的gwt.xml

....
<module rename-to='testing'>
<inherits name='com.google.gwt.user.User'/>
<inherits name='com.google.gwt.user.theme.clean.Clean'/>
<inherits name="com.google.gwt.http.HTTP" />
<inherits name="com.google.gwt.json.JSON" />
<inherits name="com.pathf.gwt.util.json.jsonwrapper" />
<entry-point class='test.client.TestingEntry'/>
<source path='client'/><source path='shared'/>
</module>

6)。 web.xml上的Servlet配置

<servlet>
<servlet-name>chatServlet</servlet-name>
<servlet-class>test.server.ChatServiceImpl</servlet-class>
</servlet>
<servlet>
<servlet-name>ChatServlet</servlet-name>
    <servlet-class>test.server.ChatSupport</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>ChatServlet</servlet-name>
    <url-pattern>/testing/chat.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>chatServlet</servlet-name>
<url-pattern>/testing/chatService</url-pattern>

我的程序在多个浏览器上运行正常,但无法在同一个浏览器上运行。我不能通过使用带有多标签的同一个浏览器来运行此程序。我想我正在使用相同的会话,我需要为每次登录创建新的会话。但我不知道如何创建它。从How to get multiple session in single browser,这可能会导致安全问题,我不应该这样做。但目前我忘记了安全问题。

  

那么,我如何才能支持多标签浏览器?

0 个答案:

没有答案