(转)淘淘商城系列——内容管理
http://blog.csdn.net/yerenyuan_pku/article/details/72845954
上文我们一起学习了内容分类管理,虽说实现了展示内容分类和新增节点这两个功能,但重命名节点和删除节点这两个功能还未开发,主要是时间太紧了,以后我一定会完善这些功能,读者如果有兴趣,也可以实现这些功能,希望大家都能学有所成。废话扯了一大堆,进入主题,本文我们将一起学习内容管理。
内容列表查询
首先,我们先来看看内容管理后台页面,如下图所示,可以看到页面分为两部分,即分为左侧内容分类和右侧内容列表两个部分。
为什么内容管理页面左侧的内容分类树形列表直接就是好的呢?其实我们看看代码就知道了,我们访问的入口是index.jsp页面,这个页面有”内容管理”模块,当我们点击内容管理时,就会去请求content.jsp页面。
我们再来看看content.jsp页面的代码,如下图所示。可以看到上面那个div就是展示我们的内容分类列表的,发起的请求与我们上文中为实现展示内容分类功能发起的请求完全一样,因此这里不用我们做任何处理就已经可以使用了。下面的div就是内容管理后台页面的右部分,用来显示内容列表,页面加载的时候,会发起url:'/content/query/list',queryParams:{categoryId:0}
这样的请求,这个请求会去查询所有内容分类下的所有内容。内容列表的展示其实跟商品列表的展示及其相似,大家可以参考我之前的淘淘商城系列——MyBatis分页插件(PageHelper)的使用以及商品列表展示这篇文章进行学习,不同的地方是内容列表要根据左边树形节点的id的变化而变化。
那么内容列表又是如何跟左边的内容分类联系起来的呢?我们看下面的js代码,如下图所示。
$(function(){...});
函数是在页面加载完之后触发执行的js代码。var tree = $("#contentCategoryTree");
显然是获取内容分类树。var datagrid = $("#contentList");
是获取内容列表。onClick : function(node){...}
这段代码的意思是当我们点击左边内容分类树的某个节点时,会做一下判断,判断是不是叶子节点,如果是叶子节点那么就给categoryId赋值为这个叶子节点的id并且会重新加载内容列表,也就意味着重新发起url:'/content/query/list'
请求,只是这时的queryParams参数中categoryId的值变成了单个叶子节点的id。
搞清了内容列表的展示原理后,照理说我们现在就应该马上实现内容列表展示的功能,但因为时间太紧,不打算实现该功能,留待以后开发。
未完,待续。。。
新增内容
我们还得从页面代码说起,新增内容是在content.jsp页面当中定义的,我们可以看到内容列表中有”toolbar:contentListToolbar”这么一句代码,这句代码的意思是定义了工具栏,工具栏中有多个功能。
我们来看看工具栏的代码,里面有新增、编辑、删除三个操作,如下所示:
var contentListToolbar = [{
text:'新增',
iconCls:'icon-add',
handler:function(){
var node = $("#contentCategoryTree").tree("getSelected");
if(!node || !$("#contentCategoryTree").tree("isLeaf",node.target)){
$.messager.alert('提示','新增内容必须选择一个内容分类!');
return ;
}
TT.createWindow({
url : "/content-add"
});
}
},{
text:'编辑',
iconCls:'icon-edit',
handler:function(){
var ids = TT.getSelectionsIds("#contentList");
if(ids.length == 0){
$.messager.alert('提示','必须选择一个内容才能编辑!');
return ;
}
if(ids.indexOf(',') > 0){
$.messager.alert('提示','只能选择一个内容!');
return ;
}
TT.createWindow({
url : "/content-edit",
onLoad : function(){
var data = $("#contentList").datagrid("getSelections")[0];
$("#contentEditForm").form("load",data);
// 实现图片
if(data.pic){
$("#contentEditForm [name=pic]").after("<a href='"+data.pic+"' target='_blank'><img src='"+data.pic+"' width='80' height='50'/></a>");
}
if(data.pic2){
$("#contentEditForm [name=pic2]").after("<a href='"+data.pic2+"' target='_blank'><img src='"+data.pic2+"' width='80' height='50'/></a>");
}
contentEditEditor.html(data.content);
}
});
}
},{
text:'删除',
iconCls:'icon-cancel',
handler:function(){
var ids = TT.getSelectionsIds("#contentList");
if(ids.length == 0){
$.messager.alert('提示','未选中商品!');
return ;
}
$.messager.confirm('确认','确定删除ID为 '+ids+' 的内容吗?',function(r){
if (r){
var params = {"ids":ids};
$.post("/content/delete",params, function(data){
if(data.status == 200){
$.messager.alert('提示','删除内容成功!',undefined,function(){
$("#contentList").datagrid("reload");
});
}
});
}
});
}
}];
我对新增操作作如下讲解:
- text指定我们看到的图标后面的文字。
- iconCls指定新增图标。
handler:function()
是当我们点击”新增”按钮时触发的函数。var node = $("#contentCategoryTree").tree("getSelected");
的意思是得到用户选中的内容分类节点。if(!node || !$("#contentCategoryTree").tree("isLeaf",node.target)){
的意思是如果选中的不是节点或者该节点不是叶子节点,那么这时就弹出一个”新增内容必须选择一个内容分类!”的提示框。如果点击的是叶子节点的话,会调用common.js文件当中定义的TT的createWindow方法初始化一个弹出框,弹出框中显示的页面是由参数url: “/content-add”指定的,也就是content-add.jsp页面。
下面我们便来看下content-add.jsp页面,表格中的字段名称与我们的数据库中表的字段是一致的,这样我们便可以直接使用逆向工程生成的代码了。
当以上页面加载完之后,会触发$(function(){...}
方法,下面我来详细分析一下该方法中的代码。
contentAddEditor = TT.createEditor("#contentAddForm [name=content]");
的意思是初始化一个富文本编辑器。TT.initOnePicUpload();
的意思是初始化单张图片上传按钮,也就是说一次只能选择一张图片(因为我们的pic和pic2字段各自对应一张图片路径)。$("#contentAddForm [name=categoryId]").val($("#contentCategoryTree").tree("getSelected").id);
这行代码的意思是把用户选择的内容分类节点的id赋值给隐藏域<input type="hidden" name="categoryId"/>
,这样我们在提交表单的时候便把内容分类id也一并提交了。
当我们点击提交超链接提交表单的时候,就会触发submitForm : function ()
方法,下面我也来详细分析一下该方法中的代码。
if(!$('#contentAddForm').form('validate')){
的意思是如果表单输入不合法,那么会提示”表单还未填写完!”。contentAddEditor.sync();
的意思是如果表单填写合法,那么富文本编辑器将与表单中的隐藏域字段(<textarea>
字段)进行内容同步。$.post("/content/save")
的意思是发起url为/content/save的请求。$("#contentAddForm").serialize()
将表单中的数据序列化为key-value形式的字符串。function(data){...}
指回调函数,if(data.status == 200){
的意思是如果返回的状态为200的话说明内容添加成功了,$("#contentList").datagrid("reload");
意思是内容添加成功后,内容列表要进行重新加载。TT.closeCurrentWindow();
的意思是关闭弹出窗口。
当我们点击重置超链接重置表单时,就会触发clearForm : function()
方法。$('#contentAddForm').form('reset');
的意思是将刚才表单中输入的内容清空。
分析了以上js代码,下面我们来实现添加内容这个功能。首先我们来编写Service层的代码。在taotao-content-interface工程下的com.taotao.content.service包中新建一个接口——ContentService.java,并在接口中添加一个insertContent方法,如下图所示。
接着我们来实现上面的接口,我们在taotao-content-service工程的com.taotao.content.service.impl包下新建一个ContentServiceImpl实现类,该类实现ContentService接口,如下图所示。
为方便大家复制,将该实现类代码贴出,如下:
/**
* 内容管理Service
* <p>Title: ContentServiceImpl</p>
* <p>Description: </p>
* <p>Company: www.itcast.cn</p>
* @version 1.0
*/
Service
public class ContentServiceImpl implements ContentService {
@Autowired
private TbContentMapper contentMapper;
@Override
public TaotaoResult insertContent(TbContent content) {
// 补全pojo的属性
content.setCreated(new Date());
content.setUpdated(new Date());
// 向内容表中插入数据
contentMapper.insert(content);
return TaotaoResult.ok();
}
}
- 1
- 2
下面我们发布一下该服务的这个接口,我们在taotao-content-service工程的spring目录下的applicationContext-service.xml配置文件中添加如下配置:
<dubbo:service interface="com.taotao.content.service.ContentService" ref="contentServiceImpl" timeout="300000" />
然后我们再来编写表现层的代码。首先我们需要在taotao-manager-web工程的springmvc.xml配置文件中添加对ContentService的引用,即要向springmvc.xml配置文件中添加如下配置:
<dubbo:reference interface="com.taotao.content.service.ContentService" id="contentService" />
接着我们需要在taotao-manager-web工程中添加ContentController类来实现新增内容这个功能。其中@RequestMapping("/content/save")
注解中的url是从content-add.jsp页面当中粘贴过来的。
在启动测试之前,我们需要先打包taotao-content到本地maven仓库。由于新增内容这个功能涉及到了taotao-manager和taotao-content这两个服务和taotao-manager-web,所以我们依次启动taotao-manager和taotao-content,然后是taotao-manager-web,启动成功之后,然后去添加一个内容,添加界面如下图所示。
点击”提交”之后,我们可以发现tb_content表中便有了我们刚才添加的内容,如下图所示。
编辑内容
由于时间紧张,在此并不实现该功能,留待以后开发。未完,待续。。。敬请期待。
删除内容
由于时间紧张,在此并不实现该功能,留待以后开发。未完,待续。。。敬请期待。