花时间买教训:
调试代码过程中,要敢于直面问题的本质,不要舍本逐末,急于搜集一大堆资料,而不仔细研究问题本质,浪费更多的时间,不值得。
先说说应用场景:
如题,前端页面利用ajax异步上传图片到服务器,交给Struts的action处理,返回json数据。
下面谈一谈踩到的一些坑,由于这个场景的例子网上已经很多,这里就不再重复造轮子,只是谈谈遇到的在这些例子中没有说到的问题
1. 为什么用ajaxfileupload?
因为我前端要采用ajax异步的方式上传图片到服务器,而我不想通过表单提交的方式,不想多一个提交按钮,希望通过input标签的onchange()方法来触发ajax。如果采用一般的ajax传数据方式,服务器端不能接收这个图片,对于一般的string类型的参数可以接收,只要定义和前端相同名字的成员变量,并提供get和set方法就可以接收了。
2. 关于ajaxfileupload.js中的status这个变量的问题?
它不是我们期望的那个ajax请求服务器后返回的status,插件ajaxfileupload.js中的仅仅通过一句status = isTimeout != “timeout” ? “success” : “error”;也就是请求超没超时来给status赋值,我觉得它并不是我action那边return的那个success或error,所以导致我ajax一直误以为接收到的status就是后台action return的直,这是一个大坑啊。后来我通过获取后台返回的数据来给status赋值,就解决了这个问题。修改部分代码如下:
requestDone = true;
var status;
//自己修改添加部分
var message = xml.responseText; //服务器返回的message内容(有些人用的result).由于struts配置返回类型是json,所以message返回的是jsonstring类型,这里判断要小心
if( message == JSON.stringify("0") ){//服务器端返回status是error
status = "error"
jQuery.handleError(s, xml, status);
}else{
try {
status = isTimeout != "timeout" ? "success" : "error";
// Make sure that the request was successful or notmodified
if ( status != "error" )
{
// process the data (runs the xml through httpData regardless of callback)
var data = jQuery.uploadHttpData( xml, s.dataType );
// If a local callback was specified, fire it and pass it the data
if ( s.success )
s.success( data, status );
// Fire the global callback
if( s.global )
jQuery.event.trigger( "ajaxSuccess", [xml, s] );
} else
jQuery.handleError(s, xml, status);
} catch(e)
{
status = "error";
jQuery.handleError(s, xml, status, e);
}
3. json对象,json字符串,普通字符串的区别?
由于我的struts.xml配置返回json类型,后台execute()方法返回String类型,这就导致callback回调函数里获取的message其实是json字符串类型,注意这与普通字符串不一样,但如果你用typeof()来检验,结果也是string类型,这也是一个坑,如上面代码注释中所讲,所以才有了if判断里的JSON.stringify(“0”),将普通字符串”0”转化为json字符串,才能比较。至于json对象,想要ajax最后通过data.**的方式获取返回数据,就得先把普通字符串转化为json字符串var d = eval(“(“+data+”)”);//将数据转换成json类型,然后通过var j = JSON.parse(data); //把json字符串转化为json对象,才能用j.name取值,转化为json对象后就能方便的取值。
<struts>
<package name="test" extends="json-default">
<action name="uploadimg" class="Tools.Controller.UploadImgAction" method="execute">
<result type="json" name="success">
<param name="contentType">
text/html
param>
<param name="root">messageparam>
result>
<result type="json" name="error">
<param name="contentType">
text/html
param>
<param name="root">messageparam>
result>
action>
package>
struts>
//将数据存储在map里,再转换成json类型数据,也可以自己手动构造json类型数据
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "tao");
map.put("id", "123");
JSONObject json = JSONObject.fromObject(map);//将map对象转换成json类型数据
message = json.toString();//给result赋值,传递给页面
is.close();
os.flush();
System.out.println(message);
return SUCCESS;
}
} catch (Exception e) {
e.printStackTrace();
message = "0";
}
message = "0";
System.out.println(message);
return ERROR;
$.ajaxFileUpload
(
{
url:'uploadimg.action',//用于文件上传的服务器端请求地址
secureuri:false,//一般设置为false
fileElementId:'imgfile',//文件上传空间的id属性
dataType:'json',//返回值类型 一般设置为json
success: function (data, status) //服务器成功响应处理函数
{
// var d = eval("("+data+")");//将数据转换成json类型,可以把data用alert()输出出来看看到底是什么样的结构
alert("status:"+status);
alert(data);
alert("data type is: "+typeof (data));
// var d = eval("("+data+")"); //把普通字符串转化为json 字符串
// var j = JSON.parse( data );
// alert(j);
// alert(typeof(j));
// alert("j.name:"+j.name);
// alert(d);
// alert("d type is: "+typeof (d));
var j = JSON.parse(data); //把json字符串转化为json对象,才能用j.name取值
alert("j type is: "+typeof (j));
alert("j : "+typeof (j));
alert("j.name:"+j.name);
// alert(d.user.name);
// alert(d.success);//从服务器返回的json中取出message中的数据,其中message为在struts2中action中定义的成员变量
$("#log_window").css('display','block');
$('.main').css('display','none');
$('body').css('background-color','#666')
},
error: function (data, status, e)//服务器响应失败处理函数
{
alert("识别失败!请尝试重新上传。。。");
window.location.reload();
}
}
)
4. 最后说说ajaxfileupload.js中方法uploadHttpData的问题?
这里我遇到网上有人说的dataType参数要大写的问题,我用大写的JSON就能成功返回数据,用小写老是返回error,后来调试到这里发现原来是var am = rx.exec(data);这句话的问题,这部分代码如下。直接看json条件里面,代码通过一个正则表达式,要去除pre标签,问题就出在var am = rx.exec(data);这句话执行之后am的值为null,后面通过am来给data赋值当然为空,可能是我这里返回的data就没有他说的pre标签,我一直用的chrome浏览器测试,或许其他浏览器会出现,所以我加了个判断,没有就直接返回data,然后就能正常返回数据了。
uploadHttpData: function( r, type ) {
var data = !type;
data = type == "xml" || data ? r.responseXML : r.responseText;
// If the type is "script", eval it in global context
if ( type == "script" )
jQuery.globalEval( data );
// Get the JavaScript object, if JSON is used.
if ( type == "json" )
{
// If you add mimetype in your response,
// you have to delete the '' tag.
// The pre tag in Chrome has attribute, so have to use regex to remove
var data = r.responseText;
var rx = new RegExp("(.*?)
","i");
var am = rx.exec(data);
if( am != null ){
//this is the desired data extracted
var data = (am) ? am[1] : ""; //the only submatch or empty
}
eval( "data = " + data ); //将数据转换成json类型
}
// evaluate scripts within html
if ( type == "html" )
jQuery("