gpt4 book ai didi

spring - 在 spring-mvc-chat github 应用程序的上下文中理解 Spring MVC 的 DeferredResult 类

转载 作者:行者123 更新时间:2023-12-04 09:52:16 24 4
gpt4 key购买 nike

我试图更好地理解以下 spring mvc 3.2 应用程序是如何工作的:https://github.com/rstoyanchev/spring-mvc-chat

我的问题是关于 deferredResult Spring MVC class .我注意到在给定时间,chatRequests 中的条目数是一样多的。映射有连接到聊天应用程序的用户。

说有 3 个用户连接 到聊天应用程序。你会看到当用户 #3 发布消息 (参见下面的 postMessage 方法),然后是 for 循环(在 postMessage 方法中)迭代 3 次 .我不明白为什么会这样。

我在下面包含示例代码。

Controller 代码:

@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);
}
}
}

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());

});

和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 Async 概念。

使用 Servlet 3.0,您可以从请求中获取 AsyncContext,将其存储在 Collection 中。

AsyncContext aCtx = request.startAsync(request, response); 

结果您的应用程序容器线程将被释放。

在单独的线程上进行一些操作并将结果写回 Servlet 响应:
aCtx.getResponse().getWriter().print(result);

从您的 DeferredResult 开始工作原理完全一样。

小例子:

现在考虑每 5 秒您就会从第三方服务中获得报价。
而且您的客户端每次都在长时间轮询您的服务器,以获取更新的内容。

你有你的 Controller 方法:
   /** 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;
}

现在让我们看看 Controller 外部的方法,它获取报价并将响应返回给客户端。
function getQuoteAndUpdateClients(){ 

String quote = getUpdatedQuoteFromThirdPartyService();

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

关于spring - 在 spring-mvc-chat github 应用程序的上下文中理解 Spring MVC 的 DeferredResult 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15357990/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com