J2EE 关于Web前端与服务端实现开发分离的实践 .
框架后台已经实现了基本的增删改查公共操作类,Action调用Service,再由Service调用公共数据库操作类。正在琢磨如何把数据传输到前台并以何种方式进行展示,而且目标是能很好的实现前端开发人员与后端开发人员工作的分离,实现通过既定好的接口进行交互。先做了一个小小的实践,是这样的。。。
大致思路是前后台传输使用具有固定结构的JSON字符串,JSON字符串中可以存在多个数据集,每个数据集有一个名字。前端与后端开发人员通过这个名字进行衔接。
并且前台使用JQuery封装了一个common.js文件用来初始化以及处理服务端传来的JSON字符串。
服务端:
通过查询返回 List list = (·····数据库中查询到的数据·····);
服务端 将list 放如Map中,键值为前端开发人员进行读取的名称。
然后将Map通过fastJson等类似工具库序列化为JSON字符串,存入request.setAttribute(······)
前端:
通过JSP中使用request.getAttribute(······)读取JSON,其实这里可以考虑固定这个getAttribute的参数值,作为框架的既定协议,然后将它放到类似COMMON.JSP中或者写入自定义标签。每个前端开发人员创建JSP的时候都要包含这个JSP或添加写好的自定义标签,由COMMON.JSP或者自定义标签将取得的JSON字符串格式化输出为一个JS对象,一个全局的JS对象。
我们取得的JSON中是一个由map("list",list)序列化成的固定结构的字符串。
这样我们可以在前端封装一些列固定的JS方法来将JSON中的数据渲染到我们想要的DOM元素中,以下JS代码将渲染数据到标签
<div id="list" spname="list" datalist="resultList" column="listTitleDic" loadingImg="true" ></div> 中。
以上标签中,spname:标签类型 datalist:对应map中的list的键值 :column:为读取数据字段键值对应的表头名称字典 loadingImg为是否显示滚动条图标选项。
使用这样的标签,前端开发人员就不需要写任何代码,连渲染数据的工作都是由框架集成的(下边代码)来完成的。
前端代码片段:
[javascript] view plaincopyprint?
- $(document).ready(function(){
- // 加载页面列表内容,因为我们标签的spname是list,之后我们可能还有select标签,checkbox标签等等,
- loadList();
- // loadSelect();
- });
- function loadList()
- {
- if($('div[spname]="list"').length !== 0 ) // 判断如果存在属性名spname值为list的div元素则显示加载图标并查找全局的JSON数据集Map或进行异步读取
- { // 遍历spname为list的Div标签
- $('div[spname]="list"').each(function(i){
- var dsName = $.trim($(this).attr("ds"));
- var currentDs = eval("dataJson.map." + dsName);// dataJson假定为我们的全局JSON数据变量
- var jTemplateId = $.trim($(this).attr("jtemplate")); //我使用了JTemplate来渲染数据,模板文件通过这个属性值来进行设置,但是上边的标签没有包含jtemplate属性,在这里不包含jtemplate属性的标签默认是按照list的结构自动生成对应模板,免去前端人员操作模板的工作。
- var ifShowLoadingImg = $.trim($(this).attr("loadingImg"));// 是否显示loading滚动条图片
- if(currentDs == undefined)
- return true; // 如果JSON数据集中不存在当前dalist值则跳出此次循环继续判断下一个
- if(ifShowLoadingImg == "true")
- {
- showLoadingImg(this); // 显示loading图片
- }
- if(jTemplateId == "")
- {
- jTemplateId = "defaultListTemplate";
- $(this).attr("jtemplate",jTemplateId);
- }
- processJTemplate(this,currentDs); //通过jTemplate模板渲染数据
- });
- }
- }
- /**
- *通过jTemplate模板渲染数据,参数:输入元素,datalist
- **/
- function processJTemplate(elementToBeRender, datalistData)
- {
- var jDefaultListTemplate;
- elementToBeRender = $(elementToBeRender);
- var columnDic = $.trim($(elementToBeRender).attr("column"));
- // 若jtemplate值为defaultListTemplate则自动生成默认列表模板
- if($.trim(elementToBeRender.attr("jtemplate")) == "defaultListTemplate")
- {
- var ifShowLoadingImg = $.trim($(elementToBeRender).attr("loadingImg"));
- jDefaultListTemplate = generateDefaultListTemplate(columnDic, datalistData);
- elementToBeRender.setTemplate(jDefaultListTemplate);
- if(ifShowLoadingImg == "true")
- setTimeout(function(){elementToBeRender.processTemplate(datalistData)},500);
- else
- elementToBeRender.processTemplate(datalistData);
- }
- else
- {
- // jDefaultListTemplate
- }
- }
- /**
- * 在传入的Dom元素中添加显示加载中GIF图片
- **/
- function showLoadingImg(element)
- {
- if(element == undefined)
- return false;
- var loadingImgUrl = basePath + "/apps/common/image/loading.gif"; // loading图片路径
- var loadingImg = $("<img>"); // 加载滚动条图片
- loadingImg.hide(); // 隐藏loading图片
- loadingImg.attr('src',loadingImgUrl);
- $(element).addClass("loadingImgAlignCenter"); // 设置容器为剧中显示
- $(element).append(loadingImg);
- loadingImg.show(); // 显示图片
- return loadingImg;
- }
- /**
- * 隐藏并删除loading图片
- **/
- function hideLoadingImg(imgElement)
- {
- $(imgElement).parent().removeClass("loadingImgAlignCenter");
- $(imgElement).remove();
- }
- /**
- * 根据传入datalistData生成默认的列表Template
- **/
- function generateDefaultListTemplate(columnDic, datalistData)
- {
- if(datalistData== undefined)
- return false; // datalistData为空不做任何操作返回false
- var templateString = new Array(); // 用于模板字符串拼接,头部
- var templateTdsString = new Array(); // 用于模板字符串拼接,内容部分
- templateString.push('<table class="gridTable" align="center" width="90%">');
- templateString.push('<thead><tr>');
- templateTdsString.push('<tbody>{#foreach $T.dataRows as record}<tr>');
- $.each(datalistData[0], function(i,n){ // 取得数据集中第一行数据
- if(columnDic != undefined)
- {
- var columnName = $.trim(eval(columnDic+"."+i));
- if(columnName != "")
- {
- templateString.push('<th>');
- templateString.push(columnName);
- templateString.push('</th>');
- }
- else
- {
- templateString.push('<th>');
- templateString.push(i);
- templateString.push('</th>');
- }
- templateTdsString.push('<td>');
- templateTdsString.push('{$T.record.');
- templateTdsString.push(i);
- templateTdsString.push('}');
- templateTdsString.push('</td>');
- }
- });
- templateString.push('</tr></thead>');
- templateTdsString.push('</tr>{#/for}</tbody>')
- return templateString.join('')+templateTdsString.join('') + '</table>';
- }//这里之所以只用字符串数组进行拼接是因为这样性能比较好,参考<a href="http://www.quirksmode.org/dom/innerhtml.html">http://www.quirksmode.org/dom/innerhtml.html</a>
$(document).ready(function(){ // 加载页面列表内容,因为我们标签的spname是list,之后我们可能还有select标签,checkbox标签等等, loadList(); // loadSelect();});function loadList(){ if($('div[spname]="list"').length !== 0 ) // 判断如果存在属性名spname值为list的div元素则显示加载图标并查找全局的JSON数据集Map或进行异步读取 { // 遍历spname为list的Div标签 $('div[spname]="list"').each(function(i){ var dsName = $.trim($(this).attr("ds")); var currentDs = eval("dataJson.map." + dsName);// dataJson假定为我们的全局JSON数据变量 var jTemplateId = $.trim($(this).attr("jtemplate")); //我使用了JTemplate来渲染数据,模板文件通过这个属性值来进行设置,但是上边的标签没有包含jtemplate属性,在这里不包含jtemplate属性的标签默认是按照list的结构自动生成对应模板,免去前端人员操作模板的工作。 var ifShowLoadingImg = $.trim($(this).attr("loadingImg"));// 是否显示loading滚动条图片 if(currentDs == undefined) return true; // 如果JSON数据集中不存在当前dalist值则跳出此次循环继续判断下一个 if(ifShowLoadingImg == "true") { showLoadingImg(this); // 显示loading图片 } if(jTemplateId == "") { jTemplateId = "defaultListTemplate"; $(this).attr("jtemplate",jTemplateId); } processJTemplate(this,currentDs); //通过jTemplate模板渲染数据 }); }}/***通过jTemplate模板渲染数据,参数:输入元素,datalist**/function processJTemplate(elementToBeRender, datalistData){ var jDefaultListTemplate; elementToBeRender = $(elementToBeRender); var columnDic = $.trim($(elementToBeRender).attr("column")); // 若jtemplate值为defaultListTemplate则自动生成默认列表模板 if($.trim(elementToBeRender.attr("jtemplate")) == "defaultListTemplate") { var ifShowLoadingImg = $.trim($(elementToBeRender).attr("loadingImg")); jDefaultListTemplate = generateDefaultListTemplate(columnDic, datalistData); elementToBeRender.setTemplate(jDefaultListTemplate); if(ifShowLoadingImg == "true") setTimeout(function(){elementToBeRender.processTemplate(datalistData)},500); else elementToBeRender.processTemplate(datalistData); } else { // jDefaultListTemplate }}/*** 在传入的Dom元素中添加显示加载中GIF图片**/function showLoadingImg(element){ if(element == undefined) return false; var loadingImgUrl = basePath + "/apps/common/image/loading.gif"; // loading图片路径 var loadingImg = $("<img>"); // 加载滚动条图片 loadingImg.hide(); // 隐藏loading图片 loadingImg.attr('src',loadingImgUrl); $(element).addClass("loadingImgAlignCenter"); // 设置容器为剧中显示 $(element).append(loadingImg); loadingImg.show(); // 显示图片 return loadingImg;}/*** 隐藏并删除loading图片**/function hideLoadingImg(imgElement){ $(imgElement).parent().removeClass("loadingImgAlignCenter"); $(imgElement).remove();}/*** 根据传入datalistData生成默认的列表Template**/function generateDefaultListTemplate(columnDic, datalistData){ if(datalistData== undefined) return false; // datalistData为空不做任何操作返回false var templateString = new Array(); // 用于模板字符串拼接,头部 var templateTdsString = new Array(); // 用于模板字符串拼接,内容部分 templateString.push('<table class="gridTable" align="center" width="90%">'); templateString.push('<thead><tr>'); templateTdsString.push('<tbody>{#foreach $T.dataRows as record}<tr>'); $.each(datalistData[0], function(i,n){ // 取得数据集中第一行数据 if(columnDic != undefined) { var columnName = $.trim(eval(columnDic+"."+i)); if(columnName != "") { templateString.push('<th>'); templateString.push(columnName); templateString.push('</th>'); } else { templateString.push('<th>'); templateString.push(i); templateString.push('</th>'); } templateTdsString.push('<td>'); templateTdsString.push('{$T.record.'); templateTdsString.push(i); templateTdsString.push('}'); templateTdsString.push('</td>'); } }); templateString.push('</tr></thead>'); templateTdsString.push('</tr>{#/for}</tbody>') return templateString.join('')+templateTdsString.join('') + '</table>';}//这里之所以只用字符串数组进行拼接是因为这样性能比较好,参考<a href="http://www.quirksmode.org/dom/innerhtml.html">http://www.quirksmode.org/dom/innerhtml.html</a>
这样前端开发人员只要知道服务端传来的dataList名称即可使用一行标签显示一个列表了。只是刚刚开始尝试,也许想法不够成熟,希望多提意见:)