Статьи

Приложение для чата в Java DWR

В этом примере приложения показано, как использовать DWR в приложении чата. Это приложение дает понять, что DWR делает разработку таких приложений для совместной работы очень простой.

Мы начинаем с создания нового проекта для нашей комнаты чата с именем проекта DWRChatRoom. Нам также нужно добавить файл dwr.jar в каталог lib и включить DWR в файле web.xml. Ниже приведен исходный код   файла dwr.xml .

<?xml ver sion="1.0" encoding="UTF-8"?>
   <!DOCTYPE dwr PUBLIC
   "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
   "http://getahead.org/dwr/dwr20.dtd">
  <dwr>
    <allow>
      <create creator="new" javascript="Login">
        <param name="class" value="chatroom.Login" />
      </create>
      <create creator="new" javascript="ChatRoomDatabase">
        <param name="class" value="chatroom.ChatRoomDatabase" />
      </create>
    </allow>
  </dwr>

Исходный код для  web.xml  выглядит следующим образом:

<?xml ver sion="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.
    com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.
    sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_
    5.xsd" id="WebApp_ID" version="2.5">
  <display-name>DWRChatRoom</display-name>
  <servlet>
    <display-name>DWR Servlet</display-name>
    <servlet-name>dwr-invoker</servlet-name>
    <servlet-class>
      org.directwebremoting.servlet.DwrServlet
    </servlet-class>
    <init-param>
      <param-name>debug</param-name>
      <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>activeReverseAjaxEnabled</param-name>
      <param-value>true</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>dwr-invoker</servlet-name>
    <url-pattern>/dwr/*</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>

Разработка пользовательского интерфейса

Следующим шагом мы создадим файлы для презентации: таблицу стилей и   файлы HTML / JSP . Для приложения требуются файлы таблиц стилей, loginFailed.html и index.jsp. Исходный код таблицы стилей выглядит следующим образом:

body{
margin:0;
padding:0;
line-height: 1.5em;
}

b{font-size: 110%;}
em{color: red;}

#topsection{
background: #EAEAEA;
height: 90px; /*Height of top section*/
}

#topsection h1{
margin: 0;
padding-top: 15px;
}

#contentwrapper{
float: left;
width: 100%;
}

#contentcolumn{
margin-left: 200px; /*Set left margin to LeftColumnWidth*/
}

#leftcolumn{
float: left;
width: 200px; /*Width of left column*/
margin-left: -100%;
background: #C8FC98;
}

#footer{
clear: left;
width: 100%;
background: black;
color: #FFF;
text-align: center;
padding: 4px 0;
}

#footer a{
color: #FFFF80;
}

.innertube{
margin: 10px; /*Margins for inner DIV inside each column (to provide padding)*/
margin-top: 0;
}

Наша первая страница — это страница входа.

Он находится в каталоге WebContent и называется index.jsp . Исходный код страницы приведен ниже:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Book Authoring</title>

<script type='text/javascript' src='/DWRChatroom/dwr/interface/Login.js'></script>
<script type='text/javascript' src='/DWRChatroom/dwr/engine.js'></script>
<script type='text/javascript' src='/DWRChatroom/dwr/util.js'></script>  

<script type="text/javascript">

function login()
{
  var userNameInput=dwr.util.byId('userName');
  var userName=userNameInput.value;
  Login.doLogin(userName,loginResult);
}

function loginResult(newPage)
{
  window.location.href=newPage;
}

</script>
</head>
<body>
<h1>Book Authoring Sample</h1>
<table cellpadding="0" cellspacing="0">
<tr>
<td>User name:</td>
<td><input id="userName" type="text" size="30"></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type="button" value="Login" onclick="login();return false;"></td>
</tr></table>
</body>
</html>

Экран входа в систему использует функцию DWR для обработки входа пользователя (классы Java представлены после веб-страниц). Функция loginResults открывает страницу сбоя или главную страницу в зависимости от результата операции входа.

Если Войти не удалось, очень простой  loginFailed.html  страница показана пользователю, thesource код , который выглядит следующим образом :

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
                      "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
                                         charset=ISO-8859-1">
<title>Login failed</title>
</head>
<body>
<h2>Login failed.</h2>
</body>
</html>

Главная страница  mainpage.jsp содержит всю клиентскую логику нашего приложения ChatRoom. Исходный код страницы выглядит следующим образом:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Chatroom</title>
<link href="styles.css" rel="stylesheet" type="text/css" />
<%
   if (session.getAttribute("username") == null
         || session.getAttribute("username").equals("")) {
      //if not logged in and trying to access this page
      //do nothing, browser shows empty page
      return;
   }
%>
<script type='text/javascript' src='/DWRChatRoom/dwr/interface/Login.js'></script>
<script type='text/javascript' src='/DWRChatRoom/dwr/interface/ChatRoomDatabase.js'></script>
<script type='text/javascript' src='/DWRChatRoom/dwr/engine.js'></script>
<script type='text/javascript' src='/DWRChatRoom/dwr/util.js'></script>  

<script type="text/javascript">
dwr.engine.setActiveReverseAjax(true);

function logout()
{
  Login.doLogout(showLoginScreen);
}

function showLoginScreen()
{
  window.location.href='index.jsp';
}

function showUsersOnline()
{
  var cellFuncs = [
          function(user) {

            return '<i>'+user+'</i>';
          }
          ];
    Login.getUsersOnline({
    callback:function(users) 
    {
      dwr.util.removeAllRows('usersOnline');
      dwr.util.addRows( "usersOnline",users, cellFuncs,
                                    { escapeHtml:false });
    }
    });
}

function getPreviousMessages()
{
    ChatRoomDatabase.getChatContent({
    callback:function(messages) 
    {
      var chatArea=dwr.util.byId('chatArea');
      var html="";
      for(index in messages)
      {
         var msg=messages[index];
         html+=msg;
      }
      chatArea.innerHTML=html;
      var chatAreaHeight = chatArea.scrollHeight;
      chatArea.scrollTop = chatAreaHeight;
    }
    });

}

function newMessage(message)
{
  var chatArea=dwr.util.byId('chatArea');
  var oldMessages=chatArea.innerHTML;
  chatArea.innerHTML=oldMessages+message;  
  var chatAreaHeight = chatArea.scrollHeight;
  chatArea.scrollTop = chatAreaHeight;
}

function sendMessageIfEnter(event)
{
  if(event.keyCode == 13)
  {
    sendMessage();
  }
}

function sendMessage()
{
    var message=dwr.util.byId('messageText');
    var messageText=message.value;
    ChatRoomDatabase.postMessage(messageText);
    message.value='';
}
</script>
</head>
<body onload="showUsersOnline();">
<div id="maincontainer">

<div id="topsection">
<div class="innertube">
<h1>Chatroom</h1>
<h4>Welcome <i><%=(String) session.getAttribute("username")%></i></h4>
</div>
</div>

<div id="contentwrapper">
<div id="contentcolumn">
<div id="chatArea" style="width: 600px; height: 300px; overflow: auto">
</div>
<div id="inputArea">
<h4>Send message</h4>
<input id="messageText" type="text" size="50"
  onkeyup="sendMessageIfEnter(event);"><input type="button" value="Send msg"
                                                      onclick="sendMessage();">
</div>
</div>
</div>

<div id="leftcolumn">
<div class="innertube">

<table cellpadding="0" cellspacing="0">
  <thead>
    <tr>
      <td><b>Users online</b></td>
    </tr>
  </thead>
  <tbody id="usersOnline">
  </tbody>
</table>

<input id="logoutButton" type="button" value="Logout"
  onclick="logout();return false;"></div>

</div>

<div id="footer">Stylesheet by <a
  href="http://www.dynamicdrive.com/style/">Dynamic Drive CSS
Library</a></div>
</div>
<script type="text/javascript">
getPreviousMessages();
</script>

</body>
</html>

Первая специфичная для комнаты чата функция JavaScript — это  getPreviousMessages () . Эта функция вызывается в конце  mainpage.jsp и извлекает предыдущие сообщения чата для этой комнаты чата.

Функция  newMessage ()  вызывается серверным Java-кодом, когда новое сообщение публикуется в чате. Функция также прокручивает область чата автоматически, чтобы показать последнее сообщение.

Функции  sendMessageIfEnter ()  и  sendMessage ()  используются для отправки пользовательских сообщений на сервер. В HTML-коде есть поле ввода для текста сообщения, а функция sendMessageIfEnter ()  прослушивает события onkeyup в поле ввода. Если пользователь нажимает ввод, вызывается функция sendMessage () для отправки сообщения на сервер.

HTML-код включает в себя область чата указанного размера и с автоматической прокруткой.

Разработка кода Java

В приложении есть несколько классов Java.

Класс Login обрабатывает вход и выход пользователя из системы, а также отслеживает зарегистрированных пользователей. Исходный код  класса Login  выглядит следующим образом:

package chatroom;

import java.util.Collection;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.directwebremoting.ScriptSession;
import org.directwebremoting.ServerContext;
import org.directwebremoting.ServerContextFactory;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.proxy.ScriptProxy;

public class Login {

   public Login() {
   }

   public String doLogin(String userName) {
      UserDatabase userDb=UserDatabase.getInstance();
      if(!userDb.isUserLogged(userName)) {
         userDb.login(userName);
         WebContext webContext= WebContextFactory.get();
         HttpServletRequest request = webContext.getHttpServletRequest();
         HttpSession session=request.getSession();
         session.setAttribute("username", userName);
         String scriptId = webContext.getScriptSession().getId();
         session.setAttribute("scriptSessionId", scriptId);
         updateUsersOnline();
         return "mainpage.jsp";
      }
      else {
         return "loginFailed.html";
      }
   }

   public void doLogout() {
      try {
         WebContext ctx = WebContextFactory.get();
         HttpServletRequest request = ctx.getHttpServletRequest();
         HttpSession session = request.getSession();
         Util util = new Util();
         String userName = util.getCurrentUserName(session);
         UserDatabase.getInstance().logout(userName);
         session.removeAttribute("username");
         session.removeAttribute("scriptSessionId");
         session.invalidate();
      } catch (Exception e) {
         System.out.println(e.toString());
      }
      updateUsersOnline();
   }

   private void updateUsersOnline() {
      WebContext webContext= WebContextFactory.get();
      ServletContext servletContext = webContext.getServletContext();
      ServerContext serverContext = ServerContextFactory.get(servletContext);
      webContext.getScriptSessionsByPage("");
      String contextPath = servletContext.getContextPath();
      if (contextPath != null) {
         Collection<ScriptSession> sessions =
                            serverContext.getScriptSessionsByPage
                                            (contextPath + "/mainpage.jsp");
         ScriptProxy proxy = new ScriptProxy(sessions);
         proxy.addFunctionCall("showUsersOnline");
      }
   }

   public List<String> getUsersOnline() {
      UserDatabase userDb=UserDatabase.getInstance();
      return userDb.getLoggedInUsers();
   }
}

Ниже приведен исходный код  класса UserDatabase 

package chatroom;

import java.util.List;
import java.util.Vector;

//this class holds currently logged in users
//there is no persistence
public class UserDatabase {

   private static UserDatabase userDatabase=new UserDatabase();

   private List<String> loggedInUsers=new Vector<String>();

   private UserDatabase() {
}

   public static UserDatabase getInstance() {
      return userDatabase;
   }

   public List<String> getLoggedInUsers() {
      return loggedInUsers;
   }

   public boolean isUserLogged(String userName) {
      return loggedInUsers.contains(userName); 
   }

   public void login(String userName) {
      loggedInUsers.add(userName);
   }

   public void logout(String userName) {
      loggedInUsers.remove(userName);
   }
}

Класс Util используется классом Login и предоставляет вспомогательные методы для примера приложения. Исходный код для  класса Util  выглядит следующим образом:

package chatroom;

import java.util.Hashtable;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;

public class Util {

   public Util() {

   }

   public String getCurrentUserName() {
      //get user name from session
      WebContext ctx = WebContextFactory.get();
      HttpServletRequest request = ctx.getHttpServletRequest();
      HttpSession session=request.getSession();
      return getCurrentUserName(session);
   }

   public String getCurrentUserName(HttpSession session) {
      String userName=(String)session.getAttribute("username");
      return userName;
   }
}

Логика функциональности серверной комнаты чата находится в классе ChatRoomDatabase. Исходный код для  ChatRoomDatabase  выглядит следующим образом:

package chatroom;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Vector;

import javax.servlet.ServletContext;

import org.directwebremoting.ScriptSession;
import org.directwebremoting.ServerContext;
import org.directwebremoting.ServerContextFactory;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.proxy.ScriptProxy;

public class ChatRoomDatabase {

   private static List<String> chatContent = new Vector<String>();

   public ChatRoomDatabase() {

   }

   public void postMessage(String message) {
      String user = (new Util()).getCurrentUserName();
      if (user != null) {
         Date time = new Date();
         StringBuffer sb = new StringBuffer();
         sb.append(time.toString());
         sb.append(" <b><i>");
         sb.append(user);
         sb.append("</i></b>:  ");
         sb.append(message);
         sb.append("<br/>");
         String newMessage=sb.toString();
         chatContent.add(newMessage);
         postNewMessage(newMessage);
      }
   }

   public List<String> getChatContent() {
      return chatContent;
   }

   private ScriptProxy getScriptProxyForSessions() {
      WebContext webContext = WebContextFactory.get();
      ServletContext servletContext = webContext.getServletContext();
      ServerContext serverContext = ServerContextFactory.get(servletContext);
      webContext.getScriptSessionsByPage("");
      String contextPath = servletContext.getContextPath();
      if (contextPath != null) {
         Collection<ScriptSession> sessions = serverContext
               .getScriptSessionsByPage(contextPath + "/mainpage.jsp");
         ScriptProxy proxy = new ScriptProxy(sessions);
         return proxy;
      }
      return null;
   }

   public void postNewMessage(String newMessage) {
      ScriptProxy proxy = getScriptProxyForSessions();
      if (proxy != null) {
         proxy.addFunctionCall("newMessage",newMessage);
      }
   }
}

Код чата удивительно прост. Содержимое чата хранится в векторе строк. Метод  getChatContent ()  просто возвращает содержимое чата Vector в браузер.

Для получения дополнительной и бесплатной загрузки проекта проверьте справочный сайт:  http://geekonjava.blogspot.com/2015/08/chat-application-using-java-dwr.html