Статьи

Приложение для чата на основе Jax-RS 2 и LongPolling

LongPolling ; также известный как Reverse Ajax или Comet, это метод Push, который без проблем работает в веб-браузерах с поддержкой Javascript.

Хотя передовые технологии Push, такие как SSE и Websocket с HTML 5, уже доступны, либо эти технологии все еще находятся в стадии разработки, либо они не полностью поддерживаются веб-браузерами, востребованы LongPolling и аналогичные методы.

В  методе LongPolling  веб-браузер отправляет запрос на сервер, и этот запрос приостанавливается на сервере до тех пор, пока не будет найден готовый ответ ( ресурс ). Ожидающий HTTP-запрос отправляется обратно в доступный исходный веб-браузер при получении ответа. Веб-браузер передает новое сообщение опроса, как только получает ответ HTTP, и этот процесс повторяется до тех пор, пока не будет готов новый ответ HTTP.

JAX-RS Асинхр

Время от времени также может вызывать сбой ожидающий запрос на опрос, исходящий от сервера, веб-браузера или текущей сетевой среды. В этом случае веб-браузер получает информацию об ошибке с сервера, отправляет запрос еще раз, а затем опрос начинается снова.

В методе LongPolling объект XMLHTTPRequest, который является объектом Javascript, может использоваться на стороне веб-браузера. Предстоящие объекты AsyncronousResponse с Jax-RS 2 могут использоваться на стороне сервера с точки зрения гибкости и удобства.

Теперь я хотел бы поделиться с вами  экземпляром приложения чата,  который содержит ассоциацию техники LongPolling и Jax-RS 2 в  Java EE 7 .

Зависимая библиотека

Приложение чата может легко работать с контейнером сервлетов, но доступная контейнерная среда должна соответствовать стандартному сервлету 3, поскольку Jax-RS 2 использует предстоящие асинхронные обработчики вместе с сервлетом 3 в контейнере.

<dependency>  
 <groupId>org.glassfish.jersey.containers</groupId>  
 <artifactId>jersey-container-servlet</artifactId>  
 <version>2.0</version>  
</dependency>

Замечания:

  • Джерси является эталонной библиотекой-исполнителем стандарта Jax-RS. http://jersey.java.net/
  • Jetty 9 или Tomcat 7 могут использоваться для поддержки Servlet 3.

Точка входа в приложение чата (Rest Endpoint)

@ApplicationPath("app")  
public class App extends Application {  
  
@Override  
public Set<Class<?>> getClasses() {  
  
Set<Class<?>> sets=new HashSet<>();  
sets.add(Chat.class);  
return sets;  
  
}  
}  

Приведенный выше объект типа класса Application, заключенный в   нотацию @ApplicationPath, содержит точку входа приложения Chat. Определенный класс Chat в HashSet описывается как ресурс Rest, принадлежащий приложению Chat.

Ресурс чата

@Path("/chat")  
public class Chat {  
  
final static Map<String, AsyncResponse> waiters = new ConcurrentHashMap<>();  
final static ExecutorService ex = Executors.newSingleThreadExecutor();  
  
@Path("/{nick}")  
@GET  
@Produces("text/plain")  
public void hangUp(@Suspended AsyncResponse asyncResp, @PathParam("nick") String nick) {  
  
waiters.put(nick, asyncResp);  
}  
  
@Path("/{nick}")  
@POST  
@Produces("text/plain")  
@Consumes("text/plain")  
public String sendMessage(final @PathParam("nick") String nick, final String message) {  
  
ex.submit(new Runnable() {  
@Override  
public void run() {  
Set nicks = waiters.keySet();  
for (String n : nicks) {  
// Sends message to all, except sender  
if (!n.equalsIgnoreCase(nick))  
waiters.get(n).resume(nick + " said that: " + message);  
}  
}  
});  
  
return "Message is sent..";  
}  
}  

Параметр типа AsyncResponse, который находится в качестве параметра в методе hangUp (..), определяет объект ответа LongPolling, который будет приостановлен на сервере. Хотя объекты  типа AsyncResponse могут предоставляться из среды Jax-RS автоматически, эти приостановленные объекты могут быть отправлены пользователю (веб-браузеру) в качестве ответа в любое время. Второй параметр [@PathParam («nick») String nick], найденный в методе hangUp (..), получает имя пользователя, которое отправляется методу по URL-адресу.

Информация о приостановленных объектах AsyncResponse принадлежит тому пользователю, который впоследствии потребуется. ConcurrentHashMap,  который является структурой Concurrent Map, может использоваться для этой цели. Таким образом, каждый объект nick-> AsyncResponse, отправляемый методу hangUp (..), будет записываться.

Второй метод класса Chat sendMessage (..) доступен через метод HTTP / POST и работает как метод RESTful, который выводит сообщения чата из веб-браузера.

Когда пользователи отправляют на сервер сообщение чата с именем Nick, метод RESTful sendMessage (..) получает эту информацию из параметров метода, и эта информация передается как асинхронная через объект ExecutorService. Конечно, можно использовать простой поток вместо объекта ExecutorService, который используется здесь.

Так же, как  новый поток ( new Runnable () {…} ) .start ();  , Ключевой проблемой здесь является запуск отправленного сообщения в фоновом режиме, а также предотвращение прерывания запроса по умолчанию / POST, точнее, предотвращение ожидания информации о сообщении, переданной Push всем пользователям.

 Пара nick  -> AsyncResponse, которая была заполнена в предыдущем методе hangUp (..) в ConcurrentHashMap, используется в объекте задачи Runnable, который находится в методе sendMessage (..), и это сообщение чата передается всем приостановленным AsyncResponse. объекты, кроме самого пользователя. Метод resume (), включенный в объекты AsyncResponse, позволяет объекту ответа @Suspended отвечать. То есть ( приостановить ) до, а затем ( возобновить ), когда ресурс сообщения чата станет готовым.

HTML-компоненты

<!DOCTYPE html>  
<html>  
<head>  
<title></title>  
<meta charset="UTF-8">  
</head>  
<body>  
<span></span>  
<table>  
<tr class="nick">  
    <td>Nick:</td>  
    <td><input id="nick"/></td>  
</tr>  
<tr>  
    <td>Message:</td>  
    <td><textarea id="message" disabled="disabled"></textarea></td>  
</tr>  
</table>  
<button>Post</button>  
<ul></ul>  
<script src="resources/jquery-1.9.1.js" type="text/javascript"></script>  
<script type="text/javascript" src="resources/chat.js"></script>  
</body>  
</html>  

На приведенной выше Html-странице есть входной объект Nick, объект текстовой области, куда будет введено сообщение, и кнопка Html, куда будет отправлено сообщение, и они выстроены в виде табличного объекта Html. Текстовая область изначально отключена, поскольку ожидается, что имя Ник будет вводиться первым от пользователя при запуске приложения. Когда пользователь отправляет первый запрос (псевдоним), неизменяемое состояние этого поля изменяется и становится сообщением доступным для записи. Кроме того, когда имя Ника отправляется на сервер (то есть, когда сделан первый запрос опроса), элемент строки таблицы HTML, который является типом класса (
<tr>
 ), скрыт.

Приложение чата должно предоставлять объекты XMLHTTPRequest и HTTP-запросы как асинхронные. В этом приложении мы получим пользу от библиотеки Jquery Ajax, которая облегчает эти операции и использует  объекты XMLHTTPRequest  в фоновом режиме. Помимо зависимости от Jquery, в проекте был написан скрипт chat.js.

chat.js

// The Polling function must be called once,  
//It will call itself recursively in case of error or performance.  
var poolIt = function () {  
$.ajax({  
    type: "GET",  
    url: "/app/chat/" + $("#nick").val(), // Access to the hangUp(..) method  
    dataType: "text", // Incoming data type text  
    success: function (message) {  
        // The message is added to the <li/> element when it is received.  
        $("ul").append("<li>" + message + "</li>");  
        poolIt(); // Link to the re-polling when a message is consumed.  
    },  
    error: function () {  
        poolIt(); // Start re-polling if an error occurs.  
    }  
});  
}  
  
// When the submit button is clicked;  
$("button").click(function () {  
  
if ($(".nick").css("visibility") === "visible") { // If <tr> line is visible;  
    $("textarea").prop("disabled", false); // Able to enter data  
    $(".nick").css("visibility", "hidden"); // Make <tr> line invisible;  
    $("span").html("Chat started..");  // Information message  
  
    // Polling operation must be initiated at a time  
    poolIt();  
}  
else  // if it is not the first time ;  
    $.ajax({  
        type: "POST", // HTTP POST request  
        url: "/app/chat/" + $("#nick").val(),// access to the sendMessage(..) method.  
        dataType: "text", // Incoming data type -> text  
        data: $("textarea").val(), // Chat message to send  
        contentType: "text/plain", // The type of the sent message  
        success: function (data) {  
  
            $("span").html(data); // It writes [Message is sent..] if successful.  
  
            // Blink effect  
            $("span").fadeOut('fast', function () {  
                $(this).fadeIn('fast');  
            });  
        }  
    });  
});  

Тестирование приложения

Поскольку   плагин Jetty 9.0.0.RC2 включен в файл конфигурации pom.xml приложения, приложение можно легко запустить с помощью

> Причал мвн:
командование войной . Доступ к приложению можно получить по адресу  http: // localhost: 8080 /  после запуска вышеуказанной цели.

Вы можете получить доступ к исходному коду и живому примеру, следуя следующему URL =>  http://en.kodcu.com/2013/06/jax-rs-2-and-longpolling-based-chat-application/