在UI部分,页面文件很简单,userMessage.jsp的内容如下:
<%@ page contentType="text/html; charset=UTF-8"%>
<html>
<head>
<title>Struts + JSONtitle>
<link rel="stylesheet" type="text/css" href="css/main.css" />
<script type="text/javascript" src="js/utilities.js">script>
<script type="text/javascript" src="js/main.js">script>
<script type="text/javascript" src="js/message.js">script>
<script>
YAHOO.util.Event.addListener(window, "load", function() {
YAHOO.TAIL.TestHome.init();
});
</script>
</head>
<body>
<div id="container">
</div>
<body>
<html>
从页面head部分可以看出,UI主要工作的有三个js文件:main.js,message.js和utilities.js。
其中,utilities.js是YUI的核心工具包;main.js主要是我自己对YUI Ajax功能的进一步封装;message.js则是页面使用的核心js文件,用来构造页面元件,和server端进行Ajax交互。其代码如下:
YAHOO.namespace("TAIL"); if (!YAHOO.TAIL.TestHome) { YAHOO.TAIL.TestHome = function () { var Dom = YAHOO.util.Dom; var Event = YAHOO.util.Event; var messageList; function loadData() { // create user editors var container = document.getElementById('container'); var userDiv = document.createElement('div'); container.appendChild(userDiv); var userLabel = document.createElement('label'); userLabel.innerHTML = 'New Test User:'; userDiv.appendChild(userLabel); var userEdit = document.createElement('input'); userEdit.type = 'text'; userEdit.id = 'user'; userDiv.appendChild(userEdit); // create msg editors var msgDiv = document.createElement('div'); container.appendChild(msgDiv); var msgLabel = document.createElement('label'); msgLabel.innerHTML = 'New Message: '; msgDiv.appendChild(msgLabel); var msgEdit = document.createElement('input'); msgEdit.type = 'text'; msgEdit.id = 'message'; msgDiv.appendChild(msgEdit); // create button var button = document.createElement('input'); button.type = 'button'; button.value = 'Add Now!'; msgDiv.appendChild(button); Event.addListener(button, 'click', addNewMessage); // create message div var msgListDiv = document.createElement('div'); msgListDiv.id = 'messagelist'; msgListDiv.style.color = 'blue'; container.appendChild(msgListDiv); JSONRequest.sendRequest( 'POST', 'home/loadMessages.action', null, { success: function(result) { messageList = result.messageList; reloadMessageList(); }, error: function(result) { alertJSONErrors(result); }, failure: function(o) { var errMsg = "Error loading message list!"; alertFailure(o, null, errMsg); } }); } function reloadMessageList() { var msgListDiv = document.getElementById('messagelist'); if (msgListDiv) { var messages = msgListDiv.childNodes; // remove first for (var i = messages.length - 1; i >= 0; i--) { msgListDiv.removeChild(messages[i]); } // new add for (var inx in messageList) { var div = document.createElement('div'); div.innerHTML = ' ' + messageList[inx].userName + ': ' + messageList[inx].content; msgListDiv.appendChild(div); } } } function addNewMessage() { var userEdit = document.getElementById('user'); var msgEdit = document.getElementById('message'); var newUser = userEdit.value; var newMsg = msgEdit.value; if (newUser && newMsg && newUser != '') { // format post data var postData = 'newUser=' + newUser + '&newMessage=' + newMsg; for (var i=0; i postData += '&messageList[' + i +'].userName=' + messageList[i].userName; postData += '&messageList[' + i +'].content=' + messageList[i].content; } // send add message request JSONRequest.sendRequest( 'POST', 'home/addMessageToUser.action', postData, { success: function(result) { messageList = result.messageList; reloadMessageList(); userEdit.value = ''; msgEdit.value = ''; }, error: function(result) { alertJSONErrors(result); }, failure: function(o) { var errMsg = "Error adding to message list!"; alertFailure(o, null, errMsg); } }); } } return { init: function() { loadData(); } }; }(); }
ps: 大家看这种js代码比较费劲,但是这种类oop的js编码风格,大家应该努力去模仿,毕竟这是一种好的习惯。大家可以翻开象YUI这些js原始文件出来看看,学习一下人家的js撰写风格。
通过userMessage.jsp中的script代码部分,大家可以看出,YAHOO.TAIL.TestHome.init()是UI的入口。进入页面,UI运行顺序为:与Struts Action交互 -> 调用init方法 -> 通过loadData()构造输入框,按钮,以及事件绑定 -> 通过JSONRequest.sendRequest的Ajax的调用来取得server端的初始messageList -> 调用成功之后,在UI初始构造messageList内容。
页面装载完毕之后,大家可以添加user和message然后点击Add Now按钮,这是触发addNewMessage()方法,这里单独把这部分代码重新罗列一下:
function addNewMessage() { var userEdit = document.getElementById("user"); var msgEdit = document.getElementById("message"); var newUser = userEdit.value; var newMsg = msgEdit.value; if (newUser && newMsg && newUser != "") { // format post data var postData = "newUser=" + newUser + "&newMessage=" + newMsg; for (var i = 0; i < messageList.length; i++) { postData += "&messageList[" + i + "].userName=" + messageList[i].userName; postData += "&messageList[" + i + "].content=" + messageList[i].content; } // send add message request JSONRequest.sendRequest("POST", "home/addMessageToUser.action", postData, {success:function (result) { messageList = result.messageList; reloadMessageList(); userEdit.value = ""; msgEdit.value = ""; }, error:function (result) { alertJSONErrors(result); }, failure:function (o) { var errMsg = "Error adding to message list!"; alertFailure(o, null, errMsg); }}); } }
该function的工作过程是:获取输入的newUser和newMsg -> 构造需要提交到server端的postData串 -> 提交Ajax请求 -> 调用成功后,重新在UI构造messageList内容。
这里提交Ajax的请求不同于loadData()中的的Ajax运用,这里多了一个postData参数,而且postData中除了构造newUser和newMsg,还将messageList的内容重新一起传回到了server端。为什么?因为StrutsTestAction默认是request级别的,不会保留上一次request的状态的。
这里构造postData中messageList部分的时候,是用类似数组的方式将List中Message对象传输到server端的。如果传递的是Map性质的对象,只需要将这里的i换成Map的key string即可,当然针对Map类型的conversion的定义也会不一样,大家可以参考Struts Type Conversion。
>>扩展建议:
这里UI部分使用的是简单的jsp文件,大家可以扩展这个应用UI部分的设计,可以结合使用Freemarker,Velocity类似的UI模板来完成构建。
例如,如果要将Struts和Velocity联合使用,同样可以通过type="velocity"的方式来定义使用vm模板,这个是Struts2默认支持的result type。