从Struts 1到Struts 2,从Dojo 1.5到Dojo 1.7、1.8,技术一直在进步,经验却需要时时更新。对于Web应用中最常碰到的Ajax请求处理,新版本的Struts 2和dojo 1.7做法就和以前不一样(在JAVA servlet中返回不同类型的AJAX response)。现在就拿一个例子说明如何从前台用Dojo通过Ajax请求将Json数据送回后台,后台检测后返回信息;顺便也看看到底新技术进步在哪里。
例子:前台录入人员信息,并保存到后台,后台返回保存后的id。
1. 在主页上增加一个按钮,点击时打开填写人员信息的对话框
main.jsp
<div style="width: 100%;">
<button id="new_person_btn" data-dojo-type="dijit.form.Button"
type="button">New Person</button>
</div>
<div class="dijitHidden">
<div data-dojo-type="test.person" style="width: 400px;"
id="new_person_dlg"></div>
</div>
<script>
require([ "dojo/ready", "dojo/on", "dijit/registry"],
function(ready, on, registry) {
ready(function() {
var new_person_btn = registry.byId("new_person_btn");
on(new_person_btn, "click", function(evt) {
registry.byId("new_person_dlg").show();
});
});
});
</script>
2. 对话框页面,可以填写人员姓名、描述、是否正式员工
person.jsp
<div data-dojo-type="dijit.form.Form" id="new_person_form"
data-dojo-id="new_person_form" encType="multipart/form-data">
<table cellspacing="10" style="width: 100%">
<tr>
<td><label for="name">Name:</label></td>
<td><input type="text" id="new_person_name" name="name"
style="width: 100%" required="true"
data-dojo-type="dijit.form.ValidationTextBox" /></td>
</tr>
<tr>
<td><label for="description">Description:</label></td>
<td><textarea id="new_person_description" name="description"
data-dojo-type="dijit.form.SimpleTextarea" rows="4"
style="width: 99%"></textarea></td>
</tr>
<tr>
<td><label for="regular">Regular:</label></td>
<td>
<div data-dojo-type="dojo.store.Memory" data-dojo-id="new_person_regular_store"
data-dojo-props="data: [{id: 'y', name: 'yes'}, {id: 'n', name: 'no'}]"></div>
<input data-dojo-type="dijit.form.ComboBox" value="yes" style="width: 100%"
data-dojo-props="store:new_person_regular_store, searchAttr:'name'" name="regular"
id="new_person_regular" />
</td>
</tr>
</table>
<div style="text-align: right; margin-right: 6px;">
<button id="new_person_submit_btn" data-dojo-type="dijit.form.Button">OK</button>
<button id="new_person_cancel_btn" data-dojo-type="dijit.form.Button">Cancel</button>
</div>
</div>
3. 对话框对应的JavaScript对象,里面包含了所有对话框相关的JS代码和事件处理。这些代码也可以放在person.jsp中,但鉴于分离视图和控制逻辑有诸多好处(MVC框架中的模型-视图分离问题(一) —— “你必将业务逻辑由显示中分离”),这儿还是分开吧。
person.js
define([ "dojo/_base/declare", "dijit/Dialog", "dijit/_WidgetBase",
"dijit/_TemplatedMixin", "dojo/on", "dijit/registry", "dojo/_base/xhr",
"dijit/form/Form", "dijit/form/ValidationTextBox",
"dijit/form/SimpleTextarea", "dojo/store/Memory", "dijit/form/ComboBox"], function(declare, Dialog, _WidgetBase,
_TemplatedMixin, on, registry, xhr) {
return declare("test.person",
[ Dialog, _WidgetBase, _TemplatedMixin ], {
title : "New Person",
postCreate : function() {
this.set('href', "dialog_newperson.action");
this.inherited(arguments);
},
onDownloadEnd : function() {
var new_person_form = registry.byId("new_person_form");
var new_person_submit_btn = registry
.byId("new_person_submit_btn");
on(new_person_submit_btn, "click", function(evt) {
if (!new_person_form.validate()) {
return false;
}
/*为了让后台认识json格式的数据,这儿有几个地方需要注意的。*/
var data = {
person : dojo.formToObject("new_person_form")
};
// Post the data to the server
xhr.post({
url : "submit_newperson.action",
handleAs : "json",
/*注意点1:json数据必须转成json格式*/
/*注意点2:json数据要放在postData中,而不是content中*/
postData : dojo.toJson(data),
/*注意点3:设置contentType为application/json */
contentType : 'application/json; charset=utf-8',
handle : function(response, ioArgs) {
return response;
}
});
});
var new_person_cancel_btn = registry
.byId("new_person_cancel_btn");
on(new_person_cancel_btn, "click", function(evt) {
registry.byId("new_person_dlg").hide();
});
this.inherited(arguments);
}
});
});
4. 为了让Struts 2能认识json格式的数据,需要引入struts2-json-plugin包。这儿用Maven管理项目,就可以直接在pom文件中加入相应dependency。如果不用Maven,则直接将jar包加入到项目buildpath中。
pom.xml
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-json-plugin</artifactId>
<version>2.3.12</version>
</dependency>
5. 重点!struts.xml中需要进行相应配置
struts.xml
<!--注意点1:在package的extends里,必须有json-default -->
<package name="workbench" namespace="/"
extends="struts-default,json-default">
<action name="submit_newperson" class="test.SubmitNewPersonAction">
<!--注意点2:在action里,加入json interceptor信息 -->
<interceptor-ref name="json">
<param name="contentType">application/json</param>
</interceptor-ref>
<!--注意点3:设置result为json格式 -->
<result type="json">
<!--注意点4:设置result包含的内容。这儿只包含result变量的数据,而没有person的数据 -->
<param name="includeProperties">result</param>
</result>
</action>
</package>
6. 保存人员信息的java对象
Person.java
public class Person {
private String name;
private String description;
private String regular;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getRegular() {
return regular;
}
public void setRegular(String regular) {
this.regular = regular;
}
}
7. 相应的action。接收传入的人员数据,返回相应的id
TestAction.java
public class TestAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private int result;
private Person person;
public void setPerson(Person person) {
this.person = person;
}
public Person getPerson() {
return person;
}
@Override
public String execute() {
System.out.println(person);
int result = savePerson(person);
return SUCCESS;
}
public int getResult() {
return result;
}
}
8. 最后返回的Response:
{"result":1}
总结
相比较Struts 1而言,Struts 2在处理接收的数据方面,确实有很大的改进。数据传送到后台后,不需要手工写代码解析json格式的数据,只要schema一致,就可以用相应的POJO对象接收。