Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
了解Spring MVC';在spring mvc聊天github应用程序的上下文中使用的DeferredResult类_Spring_Spring Mvc_Asynchronous - Fatal编程技术网

了解Spring MVC';在spring mvc聊天github应用程序的上下文中使用的DeferredResult类

了解Spring MVC';在spring mvc聊天github应用程序的上下文中使用的DeferredResult类,spring,spring-mvc,asynchronous,Spring,Spring Mvc,Asynchronous,我试图更好地理解以下spring mvc 3.2应用程序的工作原理: 我的问题是关于这个问题。我注意到,在给定的时间,chatRequests地图中的条目数量与连接到聊天应用程序的用户数量相同 假设有3个用户连接到聊天应用程序。您将看到,当user#3发布消息时(请参见下面的postMessage方法),for循环(在postMessage方法中)会迭代三次。我不明白这是为什么 我包括下面的示例代码 控制器代码: @Controller @RequestMapping("/mvc/chat")

我试图更好地理解以下spring mvc 3.2应用程序的工作原理:

我的问题是关于这个问题。我注意到,在给定的时间,
chatRequests
地图中的条目数量与连接到聊天应用程序的用户数量相同

假设有3个用户连接到聊天应用程序。您将看到,当user#3发布消息时(请参见下面的postMessage方法),for循环(在postMessage方法中)会迭代三次。我不明白这是为什么

我包括下面的示例代码

控制器代码:

@Controller
@RequestMapping("/mvc/chat")
public class ChatController {

    private final ChatRepository chatRepository;
    private final Map<DeferredResult<List<String>>, Integer> chatRequests = new ConcurrentHashMap<DeferredResult<List<String>>, Integer>();

    @Autowired
    public ChatController(ChatRepository chatRepository) {
        this.chatRepository = chatRepository;
    }

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public DeferredResult<List<String>> getMessages(@RequestParam int messageIndex) {

        final DeferredResult<List<String>> deferredResult = new DeferredResult<List<String>>(null, Collections.emptyList());
        this.chatRequests.put(deferredResult, messageIndex);

        deferredResult.onCompletion(new Runnable() {
            @Override
            public void run() {
                chatRequests.remove(deferredResult);
            }
        });

        List<String> messages = this.chatRepository.getMessages(messageIndex);
        if (!messages.isEmpty()) {
            deferredResult.setResult(messages);
        }

        return deferredResult;
    }

    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public void postMessage(@RequestParam String message) {

        this.chatRepository.addMessage(message);

        // Update all chat requests as part of the POST request
        // See Redis branch for a more sophisticated, non-blocking approach

        for (Entry<DeferredResult<List<String>>, Integer> entry : this.chatRequests.entrySet()) {
            List<String> messages = this.chatRepository.getMessages(entry.getValue());
            entry.getKey().setResult(messages);
        }
    }
}
@控制器
@请求映射(“/mvc/chat”)
公共类聊天控制器{
私有最终聊天库聊天库;
private final Map chatRequests=新ConcurrentHashMap();
@自动连线
公共聊天室控制器(聊天室存储库聊天室存储库){
this.chatRepository=chatRepository;
}
@RequestMapping(method=RequestMethod.GET)
@应答器
public DeferredResult getMessages(@RequestParam int messageIndex){
final DeferredResult DeferredResult=新的DeferredResult(null,Collections.emptyList());
this.chatRequests.put(deferredResult,messageIndex);
deferredResult.onCompletion(新的Runnable(){
@凌驾
公开募捐{
chatRequests.remove(延迟结果);
}
});
List messages=this.chatRepository.getMessages(messageIndex);
如果(!messages.isEmpty()){
deferredResult.setResult(消息);
}
返回延迟结果;
}
@RequestMapping(method=RequestMethod.POST)
@应答器
public void postMessage(@RequestParam String message){
this.chatRepository.addMessage(message);
//作为POST请求的一部分更新所有聊天请求
//有关更复杂、无阻塞的方法,请参见Redis分支
for(条目:this.chatRequests.entrySet()){
List messages=this.chatRepository.getMessages(entry.getValue());
entry.getKey().setResult(消息);
}
}
}
Javascript代码:

$(document).ready(function() {

    function ChatViewModel() {

        var that = this;

        that.userName = ko.observable('');
        that.chatContent = ko.observable('');
        that.message = ko.observable('');
        that.messageIndex = ko.observable(0);
        that.activePollingXhr = ko.observable(null);


        var keepPolling = false;

        that.joinChat = function() {
            if (that.userName().trim() != '') {
                keepPolling = true;
                pollForMessages();
            }
        }

        function pollForMessages() {
            if (!keepPolling) {
                return;
            }
            var form = $("#joinChatForm");


            that.activePollingXhr($.ajax({url: form.attr("action"), type: "GET", data: form.serialize(), cache: false,
                success: function(messages) {
                    console.log(messages);
                    for (var i = 0; i < messages.length; i++) {
                        that.chatContent(that.chatContent() + messages[i] + "\n");
                        that.messageIndex(that.messageIndex() + 1);
                    }
                },
                error: function(xhr) {
                    if (xhr.statusText != "abort" && xhr.status != 503) {
                        resetUI();
                        console.error("Unable to retrieve chat messages. Chat ended.");
                    }
                },
                complete: pollForMessages
            }));
            $('#message').focus();
        }

        that.postMessage = function() {
            if (that.message().trim() != '') {
                var form = $("#postMessageForm");
                $.ajax({url: form.attr("action"), type: "POST",
                    data: "message=[" + that.userName() + "] " + $("#postMessageForm input[name=message]").val(),
                    error: function(xhr) {
                        console.error("Error posting chat message: status=" + xhr.status + ", statusText=" + xhr.statusText);
                    }
                });
                that.message('');
            }
        }

        that.leaveChat = function() {
            that.activePollingXhr(null);
            resetUI();
            this.userName('');
        }

        function resetUI() {
            keepPolling = false;
            that.activePollingXhr(null);
            that.message('');
            that.messageIndex(0);
            that.chatContent('');
        }

    }

    //Activate knockout.js
    ko.applyBindings(new ChatViewModel());

});
$(文档).ready(函数(){
函数ChatViewModel(){
var=这个;
that.userName=ko.observable(“”);
that.chatContent=ko.可观察(“”);
该信息=ko.可观察(“”);
that.messageIndex=ko.observable(0);
this.activePollingXhr=ko.observable(null);
var keepPolling=false;
that.joinChat=函数(){
如果(that.userName().trim()!=“”){
keepPolling=true;
pollForMessages();
}
}
函数pollFormMessages(){
如果(!keepPolling){
返回;
}
变量形式=$(“#joinChatForm”);
activePollingXhr($.ajax({url:form.attr(“action”),类型:“GET”,数据:form.serialize(),缓存:false,
成功:功能(消息){
控制台日志(消息);
对于(var i=0;i
和html页面:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Chat</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <h1>Chat</h1>

    <form id="joinChatForm" th:action="@{/mvc/chat}" data-bind="visible: activePollingXhr() == null">
        <p>
            <label for="user">User: </label>
            <input id="user" name="user" type="text" data-bind="value: userName"/>
            <input name="messageIndex" type="hidden" data-bind="value: messageIndex"/>
            <button id="start" type="submit" data-bind="click: joinChat">Join Chat</button>
        </p>
    </form>

    <form id="leaveChatForm" th:action="@{/mvc/chat}" data-bind="visible: activePollingXhr() != null">
        <p>
            You're chatting as <strong data-bind="text: userName"></strong>
            <button id="leave" type="submit" data-bind="click: leaveChat">Leave Chat</button>
        </p>
    </form>

    <div data-bind="visible: activePollingXhr() != null">
        <textarea rows="15" cols="60" readonly="readonly" data-bind="text: chatContent"></textarea>
    </div>

    <form id="postMessageForm" th:action="@{/mvc/chat}" data-bind="visible: activePollingXhr() != null">
        <p>
            <input id="message" name="message" type="text" data-bind="value: message" />
            <button id="post" type="submit" data-bind="click: postMessage">Post</button>
        </p>
    </form>
</body>
<script type="text/javascript" src="../../../resources/js/jquery-1.7.2.min.js" th:src="@{/resources/js/jquery-1.7.2.min.js}"></script>
<script type="text/javascript" src="../../../resources/js/knockout-2.0.0.js" th:src="@{/resources/js/knockout-2.0.0.js}"></script>
<script type="text/javascript" src="../../../resources/js/chat.js" th:src="@{/resources/js/chat.js}"></script>

</html>

聊天
聊天

用户:
加入聊天

您正在以 离开聊天室

邮递


为了理解DeferredResult在做什么,您需要理解Servlet 3.0异步概念

使用Servlet3.0,您可以从请求中获取AsyncContext,并将其存储在某种集合中

AsyncContext aCtx = request.startAsync(request, response); 
因此,您的应用程序容器线程将被释放

在单独的线程上执行一些操作,并将结果写回Servlet响应:

aCtx.getResponse().getWriter().print(result);
从这一点来看,您的
延迟结果
的工作原理完全相同

小例子:

现在考虑每5秒你得到第三方服务的报价。 而且,您的客户端每天都会轮询您的服务器,以获取更新内容

您有自己的控制器方法:

   /** put deferred result to some HashSet. This is the same logic as you 
         store async context in servlet 3.0, those are clients who are waiting for             
         response
    **/
    @RequestMapping(value="/getQuote.do", method=RequestMethod.GET)
    @ResponseBody
    public DeferredResult<String> getQuote(){
       final DeferredResult<String> deferredResult = new DeferredResult<String>();

       someMap.put(deferredResult);
       return deferredResult;
    }
/**将延迟结果放入某个哈希集。这是第
function getQuoteAndUpdateClients(){ 

      String quote = getUpdatedQuoteFromThirdPartyService();

      for (DeferredResult<String> deferredResult: someMap){
              deferredResult.setResult(quote);
       }
 }