在项目上用到了批量删除与批量更改状态,前台使用了EasyUI的DataGrid,用到了批量更改数据状态功能。
在前台可以获取每条数据的ID,但是如何通过数组方式传递给后台?
目前有两种方式可行:
方式一:
前台代码:
// 方式一
var _list = {};
for (var i = 0; i < checkedRow.length; i++) {
_list["selectedIDs[" + i + "]"] = checkedRow[i].ID;
}
$.ajax({
url: '@Url.Action("SetCallBackStatus")',
//data: { "selectedIDs": _list },
data: _list,
dataType: "json",
type: "POST",
//traditional: true,
success: function (responseJSON) {
// your logic
alert('Ok');
}
});
注意:
1、_list 是一个对象
2、_list中的属性需要结合后台参数名称,例如”selectedIDs“,组合成类似:selectedIDs[0],selectedIDs[1]...等Request.Params
这里是最重要的,否则后台认不出来。这种方式也可以传递自定义类的数组。组合方式就是selectedIDs[0].FirstName,selectedIDs[0].LastName,selectedIDs[1].FirstName,selectedIDs[1].LastName...
3、ajax的data参数直接指定为_list
后台代码:
public ActionResult SetCallBackStatus(List<int> selectedIDs){
string result = "ok";
string errMsg = "";
return this.JsonFormat(new { result = result, errMsg = errMsg });
}
方式二:
前台代码:
var _list = [];
for (var i = 0; i < checkedRow.length; i++) {
_list[i] = checkedRow[i].ID;
}
$.ajax({
url: '@Url.Action("SetCallBackStatus")',
data: { "selectedIDs": _list },
//data: _list,
dataType: "json",
type: "POST",
traditional: true, //使用该属性放置深度序列化
success: function (responseJSON) {
// your logic
alert('Ok');
}
});
或者使用post
var url = '@Url.Action("SetCallBackStatus")';
var data = { "selectedIDs": _list };
//$.param(data,true)不会深度解析参数,返回一个字符串,字符串这种格式:"x=1&y=2&xx=3&xx=4",和GET方式在url后拼接请求参数是一样的
$.post(url ,$.param(data,true),function(data){
var obj=eval('('+data+')');
console.info('success');
});
注意:
1、_list 是一个数组。
2、ajax参数中data为{“selectedIDs”:_list}//传递的参数selectedIDs为一个数组
3、这种方式比较重要的 traditional:true,或者将 _list参数转换一下$.param(_list,true)。这里其实就是将_list作为传统的方式传递给后台。JQUERY默认是做了转换的,自动在参数后面追加了”[]“。
如:
$.param(object,trad)
参数说明
object:必需。规定要序列化的数组或对象。
trad:可选。布尔值,指定是否使用参数序列化的传统样式
有时候提交参数中有数组,设置这个可选项就显得十分必要了。
var obj = {
title: "test",
arr:[1,2,3]
};
$.param(obj,true)
--->>title=test&arr=1&arr=2&arr=3
$.param(obj)
--->>title=test&arr%5B%5D=1&arr%5B%5D=2&arr%5B%5D=3
后台代码:
同方式一
下面以实际中的例子来说明:
data是一个对象,里面有一个object对象,object的属性typeMaskValues为一个数组,有三个元素在数组中
发送请求方式:
var data={"id":row.id};
for (var key in row)
{
if (!$.isArray(row[key]) && !$.isFunction(row[key])
&& (typeof row[key]) == "object")
{
continue;
}
data["object."+key]=row[key];
}
var param = JSON.stringify(data);
var param2 = $.param(data);
var param3 = $.param(data,true);
debugger;
$.post(url,data,function(data){
});
$.post(url,param,function(data){
console.info(111);
});
$.post(url,param2,function(data){
console.info(222);
});
$.post(url,param3,function(data){
console.info(222);
});
$.ajax({
url: url,
data: data,
dataType: "json",
type: "POST",
// traditional: true, //使用该属性放置深度序列化
success: function (responseJSON) {
console.info(333);
}
});
$.ajax({
url: url,
data: data,
dataType: "json",
type: "POST",
traditional: true, //使用该属性放置深度序列化
success: function (responseJSON) {
console.info(444);
}
});
1. JSON.Stringify()处理后返回字符串:
var param = JSON.stringify(data);
因为data为一个对象,所以在转化为JSON字符串的时候以"{}"包裹,里面的数组格式为:"xx":["1","2"]
JSON字符串开始:
JSON字符串里面的数组:
2. $.param 处理后的格式为字符串,该字符串的式样为get请求在后面拼接多个参数的方式一样,
var param2 = $.param(data);
字符串开始:
里面的数组:
3.$.param 处理后的格式为字符串,该字符串的式样为get请求在后面拼接多个参数的方式一样,
var param3 = $.param(data,true);
字符串开始:
里面的数组:
POST方式向后台传递参数:
1. $.post(url,data,function(data){});
控制台的参数传递:
2. $.post(url,param,function(data){})
3.$.post(url,param2,function(data){});
4.$.post(url,param3,function(data){
console.info(222);
});
5.$.ajax({
url: url,
data: data,
dataType: "json",
type: "POST",
// traditional: true, //使用该属性放置深度序列化
success: function (responseJSON) {
console.info(333);
}
});
6.$.ajax({
url: url,
data: data,
dataType: "json",
type: "POST",
traditional: true, //使用该属性放置深度序列化
success: function (responseJSON) {
console.info(444);
}
});
针对自定义的类,也可以通过方式一jquery ajax传递给后台
例如:
// 自定义Person类
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
// 后台Action
public ActionResult SetCallBackStatus(List<Person> selectedIDs)
{
string result = "ok";
string errMsg = "";
return this.JsonFormat(new { result = result, errMsg = errMsg });
}
此时前台js可以这样写:
var _list = {};
for (var i = 0; i < checkedRow.length; i++) {
_list["selectedIDs[" + i + "].FirstName"] = checkedRow[i].FirstName;
_list["selectedIDs[" + i + "].LastName"] = checkedRow[i].LastName;
}
$.ajax({
url: '@Url.Action("SetCallBackStatus")',
//data: { "selectedIDs": _list },
data: _list,
dataType: "json",
type: "POST",
//traditional: true,
success: function (responseJSON) {
// your logic
alert('Ok');
}
});
jQuery ajax的traditional参数的作用
一般的,可能有些人在一个参数有多个值的情况下,可能以某个字符分隔的形式传递,比如页面上有多个checkbox:
$.ajax{
url:"xxxx",
data:{
p: "123,456,789"
}
}
然后后台获取参数后再分隔,这种做法有很大弊端,试问如果某一个参数值中出现了分隔符所使用的字符,会出现什么情况呢?当然后台获取的参数将与实际情况不符.
这时我想到了将上述代码写成这样:
$.ajax{
url:"xxxx",
data:{
p: ["123", "456", "789"]
}
}
如果单纯写成这样,在java后台是无法取到参数的,因为jQuery需要调用jQuery.param序列化参数,
jQuery.param( obj, traditional )
默认的话,traditional为false,即jquery会深度序列化参数对象,以适应如PHP和Ruby on Rails框架,
但servelt api无法处理,我们可以通过设置traditional 为true阻止深度序列化,然后序列化结果如下:
p: ["123", "456", "789"] => p=123&p=456&p=456
随即,我们就可以在后台通过request.getParameterValues()来获取参数的值数组了,
所以,比如我们前台有多个checkbox,前台的代码可以写成:
var values = $("input[type=checkbox]").map(function(){
return $(this).val();
}).get();
$.ajax{
url:"xxxx",
traditional: true,
data:{
p: values
}
}
关于页面向后台传递数组,自动添加[]的问题也使用拦截器:
@Service("requestParamInterceptor")
@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@SuppressWarnings("serial")
public class RequestParamInterceptor implements Interceptor {
private static final Log log = LogFactory.getLog(RequestParamInterceptor.class);
private static Pattern SCRIPT_PATTERN = Pattern
.compile("<script.*>.*<\\/script\\s*>");
private static Pattern HTML_PATTERN = Pattern.compile("<[^>]+>");
private String uriEncoding=null;
public String intercept(ActionInvocation invocation) throws Exception {
//通过核心调度器invocation来获得调度的Action上下文
final ActionContext context = invocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) context.get(ServletActionContext.HTTP_REQUEST);
HttpServletResponse response = (HttpServletResponse) context.get(ServletActionContext.HTTP_RESPONSE);
response.setCharacterEncoding(request.getCharacterEncoding());//TOMCAT WEB.XML設置的編碼方式
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Cache-Control", "no-store");
response.setDateHeader("Expires", 0);
if(uriEncoding == null)
getUriEncoding();
String method = request.getMethod();
Boolean isGet=false;
if ("get".equalsIgnoreCase(method) && request.getCharacterEncoding() != null && !request.getCharacterEncoding().equals(uriEncoding))
isGet=true;
//获取Action上下文的值栈
ValueStack stack = context.getValueStack();
Map<?, ?> paramMap = request.getParameterMap();
int flag = 0;
String lowStr = null;
Set<?> keSet = paramMap.entrySet();
for (Iterator<?> itr = keSet.iterator(); itr.hasNext();) {
try
{
@SuppressWarnings("rawtypes")
Map.Entry me = (Map.Entry) itr.next();
Object ok = me.getKey();
if(ok.equals("_"))
continue;
Object ov = me.getValue();
String[] value = new String[1];
if (ov instanceof String[]) {
value = (String[]) ov;
} else {
value[0]=ov.toString();
}
//处理后的请求参数加入值栈中 处理有些数组名后自动加了[]的情况
stack.setValue(((String)ok).replace("[]", ""), (String[])value);
}
catch(Exception e)
{
}
}
return invocation.invoke();
}
public void destroy() {
}
public void init() {
}
public void getUriEncoding()
{
String encoding=null;
Map<String, String> map = TomcatServer.getConnectorUriEncoding();
for(Map.Entry<String, String> entry : map.entrySet()) {
// System.out.println(entry.getKey() + " --> " + entry.getValue());
encoding=entry.getValue();
break;
}
try {
if(VerifyString.isEmpty(encoding))
encoding=SystemTool.getTomcatConfig("URIEncoding");
} catch (IOException e) {
}
//System.out.println(uriEncoding);
if(VerifyString.isEmpty(encoding))
uriEncoding="ISO-8859-1";
else
uriEncoding=encoding;
}
}
在sturts2的xml中配置拦截器:
<interceptors>
<interceptor name="illegalCharacter" class="requestParamInterceptor" />
<interceptor name="authority" class="authorityInterceptor"></interceptor>
<interceptor-stack name="hwhmdStack">
<interceptor-ref name="illegalCharacter"></interceptor-ref>
<interceptor-ref name="authority">
<param name="indexAction">login</param>
<param name="appCode">cost</param>
</interceptor-ref>
<interceptor-ref name="defaultStack" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="hwhmdStack" />
又例如:
java的Action:
private List<PersonnelObject> personnelObjects;
public List<PersonnelObject> getPersonnelObjects() {
return personnelObjects;
}
public void setPersonnelObjects(List<PersonnelObject> personnelObjects) {
this.personnelObjects = personnelObjects;
}
前台:
错误写法1.
//下面这么写后台无法获取personnelObjects的值
var data = {};
var personnelList = new Array();
for(var i = 0;i<checkRows.length;i++){
personnelList.push(checkRows[i]);
}
data["personnelObjects"] = personnelList;
$.post(funUrl,data,function(data){});
google请求参数:
错误写法2:
//这么写会发现后台personnelObjects也是为null,接受不到值
var data = {};
for(var i = 0;i<checkRows.length;i++){
personnelList.push(checkRows[i]);
data["personnelObjects["+i+"]"] = checkRows[i];
}
$.post(funUrl,data,function(data){})
google请求参数为:
但是如果这么写:
//这么写会发现后台personnelObjects有值,集合中的每个对象的ID有值
var data = {};
for(var i = 0;i<checkRows.length;i++){
personnelList.push(checkRows[i]);
data["personnelObjects["+i+"].id"] = i;//只传递数组中的每个对象的ID值
}
$.post(funUrl,data,function(data){})
疑问:传递完整的每个对象,后台接受不到值;如果传递的是每个对象的某个属性,则会获取到对应的值
进一步测试
//这么写会发现后台personnelObjects有值,集合中的每个对象的ID有值
var data = {};
for(var i = 0;i<checkRows.length;i++){
personnelList.push(checkRows[i]);
//data["personnelObjects["+i+"].id"] = i;//只传递数组中的每个对象的ID值
for (var key in checkRows[i]){
if (!$.isArray(checkRows[i][key]) && !$.isFunction(checkRows[i][key])
&& (typeof checkRows[i][key]) == "object")
{
continue;
}
data["personnelObjects["+i+"]."+key]=checkRows[i][key];
}
}
$.post(funUrl,data,function(data){})
google浏览器的请求参数:
发现这种写法,后台也能够正常的获取.
好像向后台传递参数的时候,如果属性在符号".id"可以正常解析,但是[id]不能够解析.
接下来测试$.param:
var aa = $.param(data);//这个就是正常的jquery的参数序列化
var bb = $.param(data,true);
aa的参数序列化格式为:
bb的参数格式为:
可见:
$.param(data,true)的浅度序列化并没有解析出object对象,所以在传递参数的时候并没有能够真正的给后台传值.
$.param(data)就能够正确的解析出来
总结:
普通参数和基本类型数组可以使用$.param(data,true);
如果要传递非基本类型数组,那么就要循环数组中的每个对象,利用"."来赋值参数属性