ich besser bin versucht zu verstehen, wie die folgende Frühjahr Mvc 3.2 Anwendung funktioniert: https://github.com/rstoyanchev/spring-mvc-chatdie Spring MVC ist DeferredResult Klasse im Rahmen der Feder-mvc-chat Github Anwendung Legendes
Meine Frage ist, über die deferredResult Spring MVC class. Ich habe festgestellt, dass zu einer bestimmten Zeit so viele Einträge in der Karte chatRequests
vorhanden sind, wie Benutzer mit der Chat-Anwendung verbunden sind.
Sagen Sie, es gibt 3 Benutzer verbunden mit der Chat-Anwendung. Sie werden sehen, wenn Benutzer # 3 eine Nachricht (siehe postMessage-Methode unten), dann die For-Schleife (in PostMessage-Methode) iteriert dreimal. Ich kann nicht herausfinden, warum das so ist.
Ich füge Beispielcode unten ein.
-Code für 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-Code:
$(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());
});
und HTML-Seite:
<!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>
Nun, ich denke, wenn Sie das mit dem Autor von "DeferredResult" besprochen haben, dann sollten Sie die gesamte Kommunikation irgendwo platzieren. Damit jeder mehr darüber erfährt. – rd22
Ich denke [diese Reihe von Folien] (http://rstyanyanchev.github.io/spring-mvc-32-update/#8) von Rossen Stoyanchev wirft auch etwas Licht auf das Thema. –