ajax.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. /**通用ajax服务的定义对象
  2. * services可以是单个服务对象,也可以是service服务数组
  3. * 具体服务的定义请参考appendServices成员函数
  4. */
  5. function Service(services){
  6. this.services=[];
  7. this.shareParameters={};
  8. /**添加共享参数,在这里统一设置共享参数
  9. */
  10. this.addShareParameters=function(shareParameters){
  11. this.shareParameters=shareParameters;
  12. return this;
  13. };
  14. /**
  15. * 批量调用一般服务
  16. * 入参可以是一个调用服务的数组或者单个调用服务
  17. * 每个调用服务有下面的属性
  18. * serviceId 服务Id,不可为空
  19. * method 服务方法名,不可为空
  20. * parameters 服务参数,必须是object,object的属性名代表参数名,属性值代表参数值。
  21. * transform:结果集的转换规则(返回结果集合List<Map<String,Object>>时才会用到):null(无转换)、'firstRow'(取首行)、'breakdown'(分列),值不区分大小写
  22. * shareResults 共享服务的返回结果,默认不共享false,如果后续服务需要使用到结果里面的参数,
  23. * 那么就需要明确指定。该参数可以是 boolean,array或者object,为true时表示全部共享;
  24. * 数组可以指定返回值中需要共享的值的名,这样返回值的键值对应关系共享;
  25. * object可以额外指定共享名的别名,当要求返回值以新的字段名共享、
  26. * 或者一个以多个新别名共享时就需要用到这种类型,object的属性名表示结果集中需要共享的字段名,
  27. * 属性值表示新的字段名;
  28. * 参数共享处理列表结果集时,整个结果集的数据存放在别名为空串的特殊key上。如果本业务没有返回结果,那么参数共享无效。
  29. * useShare 使用共享参数标志,定义方式与shareResults一样,意义正好想对应。该参数指明如果从共享参数中获取要的值。
  30. * shareNotNull 校验共享参数是否为空,作为useShare的附属属性。
  31. * 有时希望如果获取到的共享参数是空的,那么不继续执行,那么可以在这里指定哪些一定不能为空。
  32. * 目前只允许三种取值,null,true和别名数组,null表示不校验,true表示全校验,别名数组表示只校验指定的值(别名是指useShare中新的别名,并非共享池里面的共享别名)。
  33. */
  34. this.appendServices=function(services){
  35. if(!services){
  36. return this;
  37. }
  38. //默认按批量形式添加服务,如果是单个,那么用数组包装
  39. var tmp_services=services;
  40. if(!$.isArray(tmp_services)){
  41. tmp_services = [tmp_services];
  42. }
  43. //每个service必须有serviceId,method
  44. for(var index=0 ;index< tmp_services.length;index++){
  45. //检查必录项
  46. if(!tmp_services[index].serviceId||!tmp_services[index].method){
  47. _FW.oFtl.fnAlert('服务定义的serviceId和method不可为空');
  48. return this;
  49. }
  50. //检查可选项
  51. if(tmp_services[index].parameters){
  52. if(typeof tmp_services[index].parameters !='object'
  53. ||jQuery.isArray(tmp_services[index].parameters)){
  54. _FW.oFtl.fnAlert('服务定义的参数必须是map!');
  55. return;
  56. }
  57. }
  58. //如果指定了transform,那么值只能是规定的
  59. if(tmp_services[index].transform){
  60. if('FIRSTROW'!=tmp_services[index].transform.toUpperCase()
  61. &&'BREAKDOWN'!=tmp_services[index].transform.toUpperCase()){
  62. _FW.oFtl.fnAlert('transform属性不正确');
  63. return this;
  64. }
  65. }
  66. //shareResults
  67. //转换shareResults,统一转换成map,或者boolean
  68. shareResults = tmp_services[index].shareResults;
  69. if(shareResults){
  70. if(typeof shareResults =='boolean'){
  71. if(!shareResults){
  72. shareResults =null;
  73. }
  74. }else if(jQuery.isArray(shareResults)){
  75. //转化为map
  76. shareResults={};
  77. $.each(tmp_services[index].shareResults,function(indexInArray, valueOfElement){
  78. shareResults[valueOfElement]=valueOfElement;
  79. });
  80. tmp_services[index].shareResults =shareResults;
  81. }
  82. }
  83. //useShare
  84. useShare = tmp_services[index].useShare;
  85. if(useShare){
  86. if(typeof useShare =='boolean'){
  87. if(!useShare){
  88. tmp_services[index].useShare =null;
  89. }
  90. }else if(jQuery.isArray(useShare)){
  91. //转化为map
  92. useShare={};
  93. $.each(tmp_services[index].useShare,function(indexInArray, valueOfElement){
  94. useShare[valueOfElement]=valueOfElement;
  95. });
  96. tmp_services[index].useShare =useShare;
  97. }
  98. }
  99. //shareNotNull,只允许true和字符串数组
  100. shareNotNull = tmp_services[index].shareNotNull;
  101. if(shareNotNull){
  102. if(typeof shareNotNull !=='boolean' && !jQuery.isArray(shareNotNull)){
  103. _FW.oFtl.fnAlert('参数[shareNotNull]的取值必须是true或者字符串数组!');
  104. return this;
  105. }else if(shareNotNull ===false){
  106. tmp_services[index].shareNotNull = null;
  107. }
  108. }
  109. }
  110. this.services=this.services.concat(tmp_services);
  111. return this;
  112. };
  113. /**定义添加直接调用存储过程的服务
  114. * 可以批量添加存储过程。每个存储过程服务的有以下属性:
  115. * procName、parameters、shareResults、useShare,
  116. * 其中procName指明存储过程的名称,其他的请参考appendServices;parameters中的参数名不能是procName
  117. * 批量添加存储过程时,用数组存储各个存储过程作为参数传入即可。
  118. * ...
  119. */
  120. this.appendProc=function(procedures){
  121. if(!procedures){
  122. return this;
  123. }
  124. //默认按批量形式添加服务,如果是单个,那么用数组包装
  125. tmp_procedures=procedures;
  126. if(!$.isArray(tmp_procedures)){
  127. tmp_procedures = [tmp_procedures];
  128. }
  129. //遍历,一个一个的处理
  130. procedure_services =[];
  131. for (var index=0;index< tmp_procedures.length;index++){
  132. //必须有configId属性
  133. procedure = tmp_procedures[index];
  134. if(!procedure.procName){
  135. _FW.oFtl.fnAlert('存储过程服务必须指定procName属性');
  136. return this;
  137. }
  138. procedure = $.extend(true,{},procedure,
  139. {serviceId:'directJdbcService',method:'savePointProcedure'
  140. ,parameters:{'':procedure.procName}});
  141. //去掉存储过程名称
  142. delete procedure.procName;
  143. //添加到服务列表
  144. procedure_services.push(procedure);
  145. }
  146. return this.appendServices(procedure_services);
  147. };
  148. /**定义添加调用预定义查询语句的服务
  149. * 可以批量添加查询语句。每个查询服务的包括以下属性:
  150. * configId、transform、indices,parameters、shareResults、useShare。
  151. * configId是Mapper.xml中的配置ID(注意写上空间名)
  152. * parameters是传递给configId的参数
  153. * transform:结果集的转换规则:null(无转换)、'firstRow'(取首行)、'breakdown'(分列),值不区分大小写
  154. * ,该参数要求传入字符串数组类型,元素值指明参数Map中的一个参数名。
  155. * 其它属性将作为查询语句的备用参数。其他的请参考appendServices;
  156. * 批量添加查询服务时,用数组存储各个查询服务作为参数传入即可。
  157. * ...
  158. */
  159. this.appendQuery=function(querys){
  160. if(!querys){
  161. return this;
  162. }
  163. //默认按批量形式添加服务,如果是单个,那么用数组包装
  164. tmp_querys=querys;
  165. if(!$.isArray(tmp_querys)){
  166. tmp_querys = [tmp_querys];
  167. }
  168. //遍历,一个一个的处理
  169. query_services = [];
  170. for (var index=0;index<tmp_querys.length;index++){
  171. //必须有configId属性
  172. var query = tmp_querys[index];
  173. if(!query.configId){
  174. _FW.oFtl.fnAlert('查询服务必须指定configId属性');
  175. return this;
  176. }
  177. //参数索引放入参数串中
  178. query = $.extend(true,{},query,
  179. {serviceId:'commService',method:'query'
  180. ,parameters:{'_commDo':query.configId}});
  181. //去掉存储过程名称,和参数索引
  182. delete query.configId;
  183. //添加到服务列表
  184. query_services.push(query);
  185. }
  186. return this.appendServices(query_services);
  187. };
  188. /**定义触发ajax的事件
  189. * message:本次ajax请求的名称,可选。
  190. * success:处理成功后触发的函数,原型是function(data)。
  191. * error:处理是否时触发的函数,原型是function(XMLHttpRequest, textStatus, errorThrown);
  192. * async:同步或是异步,同步为false、异步是true
  193. */
  194. this.sentAjax=function(message,success,error,async){
  195. var that=this;
  196. if(this.services.length==0){
  197. _FW.oFtl.fnAlert('请至少添加一个服务');
  198. return;
  199. }
  200. var t_async = true;
  201. var t_message = message;
  202. var t_success = success;
  203. var t_error = error;
  204. if(jQuery.isFunction(message)){
  205. t_message = '正在请求服务,请稍候...';
  206. t_success =message;
  207. t_error = success;
  208. }else if (typeof message != 'string'){
  209. _FW.oFtl.fnAlert('入参错误,请检查程序!');
  210. return ;
  211. }
  212. if(async!=null&&typeof async=='boolean'){
  213. if(!async){
  214. t_async = false;
  215. }
  216. }
  217. var thisrequest={};
  218. $.ajax({
  219. url:contextPath+'/ajaxAdapter.do'
  220. ,data:{parameters:JSON.stringify(this.services),shareArguments:JSON.stringify(this.shareParameters)}
  221. ,dataType :'json'
  222. ,cache:false
  223. ,async:t_async
  224. ,contentType: "application/x-www-form-urlencoded; charset=utf-8"
  225. ,type:'post'
  226. ,error:function (request, textStatus, errorThrown) {
  227. if(!t_error){
  228. _FW.oFtl.fnAlert('数据请求错误!');
  229. }else{
  230. t_error(request, textStatus, errorThrown);
  231. }
  232. }
  233. ,success:function (data, textStatus) {
  234. if(data!=null && data[headtoken]!=null){
  235. token=data[headtoken];//更新全局变量token标志
  236. }
  237. //校验业务处理是否正确执行
  238. if("1"!=data.FHZ){//出错了,弹出错误提醒
  239. if ("loginTimeout" == data.FHZ) {
  240. if(window.confirm(data.MSG||'')){
  241. window.top.location.href=_selfUrl;
  242. }
  243. } else if("CSRF" == data.FHZ){
  244. showMsg(data.MSG||'',3);
  245. return;
  246. } else {
  247. if(t_error){
  248. t_error(data.MSG||'', 'serviceErr', data.MSG);
  249. }else{
  250. _FW.oFtl.fnAlert(data.MSG||'');
  251. }
  252. }
  253. }else if(!t_success){
  254. }else{
  255. t_success(data.RTN);
  256. }
  257. }
  258. ,beforeSend:function(XMLHttpRequest ){
  259. var cToken = $.cookie(headtoken) || token;XMLHttpRequest.setRequestHeader(headtoken,cToken);
  260. $.data(thisrequest,'msg',showMsg(t_message,-1));
  261. //createProgressBar();
  262. }
  263. ,complete:function( ){
  264. hideMsg($.data(thisrequest,'msg'));
  265. }
  266. });
  267. };
  268. //添加参数
  269. if(services){
  270. this.appendServices(services);
  271. }
  272. /**
  273. * 将JSON序列化为一个字符串,
  274. * 相对于JSON.stringify,{}中的键值对会按照key升序顺序输出。
  275. */
  276. function stringify(o){
  277. var toString = Object.prototype.toString;
  278. var s = "";
  279. if(null === o){
  280. return "null";
  281. }else if(undefined === o){
  282. return "undefined";
  283. }else if("[object Function]" === toString.call(o)){
  284. return "\"[object Function]\"";
  285. }else if("[object Object]" === toString.call(o)){
  286. s += "{";
  287. var arr = [];
  288. for(var key in o){
  289. arr.push(key);
  290. }
  291. arr.sort();
  292. for(var i in arr){
  293. var key = arr[i];
  294. s += "\"" + key + "\":" + stringify(o[key]) + ",";
  295. }
  296. s = s.substring(0,s.length-1);
  297. s += "}";
  298. }else if("[object Array]" === toString.call(o)){
  299. s += "[";
  300. for(var i in o){
  301. s += stringify(o[i]);
  302. if(i != o.length-1){
  303. s += ",";
  304. }
  305. }
  306. s += "]";
  307. }else if("[object Number]" === toString.call(o)){
  308. if(isFinite(o)){
  309. return "" + o;
  310. }else if(isNaN(o)){
  311. return "NaN";
  312. }else if(Infinity === o){
  313. return "Infinity";
  314. }
  315. }else if("[object String]" === toString.call(o)){
  316. return "\"" + o + "\"";
  317. }else if("[object Boolean]" === toString.call(o)){
  318. return true === o?"true":"false"
  319. }else if("[object RegExp]" === toString.call(o)){
  320. return "/"+ o.source +"/"
  321. + (o.global?"g":"")
  322. + (o.ignoreCase?"i":"")
  323. + (o.multiline?"m":"");
  324. }else{
  325. return "\"" + toString.call(o) + "\"";
  326. }
  327. return s;
  328. }
  329. }
  330. /**
  331. * 在页面的左上角显示错误消息
  332. * @param msg 消息内容
  333. * @param timeout 秒为单位,0或者负数表示不自动隐藏
  334. * @author 吴英德
  335. **/
  336. var framework_message_layer;
  337. var clearIntervalID;
  338. function showMsg(msg,delay){
  339. var recurrectLocation=function(){
  340. if(framework_message_layer==null)
  341. {clearInterval(clearIntervalID);return;}
  342. var posX,posY;
  343. if (window.innerHeight) {
  344. posX = window.pageXOffset;
  345. posY = window.pageYOffset;
  346. }
  347. else if (document.documentElement && document.documentElement.scrollTop) {
  348. posX = document.documentElement.scrollLeft;
  349. posY = document.documentElement.scrollTop;
  350. }
  351. else if (document.body) {
  352. posX = document.body.scrollLeft;
  353. posY = document.body.scrollTop;
  354. }
  355. framework_message_layer.style.top=String(posY+10)+'px';
  356. framework_message_layer.style.right=String(posX+10)+'px';
  357. };
  358. if(framework_message_layer == null){
  359. framework_message_layer=document.createElement('div');
  360. framework_message_layer.className='err_message_blank_board';
  361. document.body.appendChild(framework_message_layer);
  362. clearIntervalID=window.setInterval(recurrectLocation,100);
  363. recurrectLocation();
  364. }
  365. var my_div = document.createElement('div');
  366. my_div.className='err_message';
  367. //Element.extend(my_div);
  368. my_div.innerHTML=msg;
  369. //增加判断:已经存在的信息,则不再重复提示
  370. if ($(".err_message:contains("+msg+")",document.body).length == 0) {
  371. framework_message_layer.appendChild(my_div);
  372. recurrectLocation();
  373. }
  374. if(delay>0){
  375. setTimeout(function(){
  376. jQuery(my_div).remove();
  377. if(jQuery(framework_message_layer).is(':empty')){
  378. jQuery(framework_message_layer).remove();
  379. window.clearInterval(clearIntervalID);
  380. framework_message_layer=null;
  381. }
  382. },delay*1000);
  383. }else{
  384. return my_div;
  385. }
  386. }
  387. /**隐藏右上角对应的消息
  388. * @param object 某消息对象,来自showMsg的返回值
  389. */
  390. function hideMsg(object){
  391. jQuery(object).remove();
  392. }