门户系统的搭建、显示商城首页、内容管理系统的实现、首页轮播图展示实现

8.28~8.29
1、门户系统的搭建
2、显示商城首页
3、内容管理系统的实现
a) 内容分类管理
b) 内容管理
4、首页的轮播图展示实现

1、门户系统的搭建
门户属于前台系统 :面向广大的互联网网民。
后台系统:面向维护人员,入住的商家,使用。

我们目前只是完成了后台管理系统和商品服务,还有很多没有实现,淘淘商城首页的展示需要用到商城门户工程和内容服务工程。这节我们便学习一下商城门户的搭建。
Taotao-portal-web war

SEO:搜索引擎优化,为了提高网站的流量,提高在各搜索引擎中的搜索排名,需要进行优化,那么可以为动态网站伪静态化,以提高排名。
pom.xml
我们在taotao-portal-web工程添加相关依赖,如下所示,注意最下方tomcat插件工程配置的端口号是8082(因为8080和8081已经被占用了)。
src/main/webapp/WEB-INF/web.xml
可以看到我们配置的拦截器拦截的请求是以.html结尾的。我们可以称之为"伪静态",之所以称伪静态是因为我们可以把各种动态请求都写成以.html结尾,这样响应的是动态数据,但由于请求是以.html结尾的,浏览器便认为要访问静态资源。SEO(搜索引擎优化)便喜欢收录以.html结尾的请求,从而有利于搜索排名。
src/main/resources/resource/resource.properties
src/main/resources/spring/springmvc.xml
配置的controller的扫描包是com.taotao.portal.controller
src/main/java/com.taotao.portal.controller
src/main/webapp/css、images、js
其中css、images、js直接放到webapp目录下,这点与taotao-manager-web工程不一样,原因是taotao-manager-web工程配置的拦截器拦截的是以"/“结尾的请求这样的话,我们可以通过配置资源映射来访问WEB-INF目录下的静态资源,但是现在由于拦截器拦截的请求是以”.html"结尾的,springmvc根本就不会去拦截静态资源,这样即使配置资源映射也不管用。因此放到WEB-INF的话,将无法访问到这些静态资源,因此需要直接放到webapp目录下才行。
src/main/webapp/WEB-INF/jsp
那么为何jsp要放到WEB-INF下面呢?这是因为我们在springmvc.xml文件中配置了视图解析器,指定了访问的jsp目录在WEB-INF目录下,因此要放到WEB-INF下。
下面我们来访问商城首页
src/main/java/com.taotao.portal.controller/IndexController.java
RequestMapping("/index")表示拦截以index.html结尾的请求(因为在springmvc拦截器配置时我们配置了以
.html结尾的请求会被拦截)。但是我们用户的习惯是输入域名之后直接就可以访问官网首页,不能要求用户再输入index.html,因此我们需要配置一下web.xml。(一般:jd,taobao访问时直接访问域名我们这里能否直接访问: http://localhost:8082/(http://localhost:8082/相当于访问域名,后面部署的时候将会换成域名访问)答案是否定的,要想实现此功能,修改:web.xml。添加红色部分如下:) web.xml文件中的配置的是默认的访问页(原来是index.jsp,现在是index.html),也就是请求过来后会默认访问index.html,由于这个页面并不存在,DispatcherServlet会处理该请求,这时由于请求是以index.html结尾了,因此满足了Controller层的拦截要求,因此便执行showIndex方法,返回"index",由于springmvc.xml中配置了视图解析器,会自动在"index"的后面加上".jsp",这样请求便成了访问index.jsp,index.jsp是我们的商城首页,因此便可以访问到商城首页了。
启动taotao-portal-web工程

启动后,我们在地址栏输入http://localhost:8082即可访问到商城首页,如下图所示,现在中间广告位那块还没有实现,因此没有图片。

首先找到springmvc中的配置的欢迎页面,所以先从那里找,找不到的话进入servlet,也就是controller层的代码,请求index,因为在前面设置了拦截html形式的,有,那么就访问即可

2、显示商城首页

3、内容管理系统的实现
首页大广告位开发实现分析
可以根据首页大广告位的数据结构设计一张表,进行增删改查管理
其他部分的展示内容同样可以设计表,进行增删改查
存在的问题:
如果每一个前端展示内容(大广告位、小广告位等等),单独建立表,进行CRUD操作,会有以下问题:
1.首页页面信息大量堆积,发布显的异常繁琐沉重;
2.内容繁杂,管理效率低下;
3.许多工作都需要其他技术人员配合完成;
4.改版工作量大,维护,扩展性差;
使用内容管理系统解决以上问题。

内容管理系统
**内容管理系统(content management system,CMS)**是一种位于WEB 前端(Web 服务器)和后端办公系统或流程(内容创作、编辑)之间的软件系统。
内容的创作人员、编辑人员、发布人员使用内容管理系统来提交、修改、审批、发布内容。这里指的“内容”可能包括文件、表格、图片、数据库中的数据甚至视频等一切你想要发布到Internet网站的信息。
就是后台管理维护前台的页面和页面中的内容可以动态展示。

动态展示分析
对首页展示功能进行分析,抽取,发现应当有以下的字段属性:
1.有图片
2.有链接
3.有标题
4.有价格
5.图片提示
6.包含大文本类型,可以作为公告
把首页的每个展示功能(大广告位,淘淘快报等),看作是一个分类
每个展示功能里面展示的多条信息,看作是分类下的内容
例如:首页大广告,对应的是大广告分类,而大广告位展示的多张图片,就是大广告分类下的内容
前台需要获取大广告的图片,只需要根据大广告的id查询对应的内容即可
需要一个内容分类表和一个内容表。内容分类和内容表是一对多的关系。

a) 内容分类管理
我们以京东的首页为例,如下图所示,可以看到内容显示是分组显示的,广告位轮播图是一组,轮播图下面那两张图片是一组,右边的"促销"、"公告"是一组,但是它与轮播图又有所不同,不同之处在于它下面分了两个小组,每个小组下面有标题列表,每个标题都是一个链接,点击"促销"这组的任何一个标题进入会是一个新的网站,点击"公告"这组的任何一个标题进去则是公告的具体内容(相当于一篇文章)。"更多"表示还有其它分组。另外"京东秒杀"这也是一组,这组内容的特点是有标题有图片有价格。"发现好货"这组则是有图片有标题。

从上图京东首页的展示不难看出,我们应该将内容进行分类,每个分类下面有多条内容,它们是一对多的关系,这样的关系就适合用两张表来进行存储。一张表示内容分类表,另一张表示内容表。
首先我们来看下内容分类表tb_content_category,如下图所示。表中有parent_id字段,这样便可以实现树形分级展示,分类要有分类名称(name字段),status字段用来表示该分类目前是否应该显示(如果已经逻辑删除了,那么便不再显示了),sort_order则是同级类目的展现次序,is_parent字段直接记录是否是父级类目(这个字段在树形展示时很有用)。

下面我们便来看一下内容表,内容表中肯定是有内容分类表的外键的(category_id),内容展示有的有标题,因此需要标题(title)这么一个字段,有的文章是有小标题的,因此我们应该加上小标题字段(sub_title),有的内容需要对标题进行描述,因此需要标题描述字段(title_desc),链接字段是必须要有的,因为内容涉及最多的便是跳转。之所以这张表设计了两个图片字段,是因为考虑到不同的显示屏所显示的图片会不一样,宽屏则应该显示宽屏图片,窄屏则应该显示窄屏图片。

下面我们来搭建内容工程
可以参考taotao-manager创建。
taotao-content:聚合工程打包方式pom
|–taotao-content-interface jar
|–taotao-content-Service war
pojo层//直接依赖POJO过来
dao层//直接依赖dao过来

Taotao-content pom

添加taotao-content-interface模块jar

新建taotao-content-service模块war

至于dao和pojo两个模块我们不用在taotao-content工程再新建一遍了,因为我们在taotao-manager工程当中便创建好了,我们只需要引用这两个模块就可以了。

taotao-content的pom.xml
添加对taotao-common工程的依赖,我们最好启动聚合工程,因此我们在聚合工程配置tomcat启动插件,8080、8081、8082都已经被占用了,我们这里使用8083,如下所示。
taotao-content-interface的pom.xml
添加对taotao-manager-pojo的依赖
taotao-content-service的pom.xml
添加taotao-manager-dao、taotao-content-interface、spring、dubbo的依赖

src/main/resources/mybatis/SqlMapConfig.xml
src/main/resources/properties/db.properties
src/main/resources/spring/applicationContext-dao.xml、applicationContext-service.xml、applicationContext-trans.xml
需要修改扫描的包为"com.taotao.content.service" dubbo服务名称修改为"taotao-content",dubbo服务向外暴露的端口为"20881"(每发布一个服务就要更改一个端口)
修改applicationContext-trans.xml文件,修改切面的包为com.taotao.content.service。

src/main/java/com/taotao/content/service
src/main/java/com/taotao/content/service/impl
src/main/resources/log4j.properties
src/main/webapp/WEB-INF/web.xml修改为"taotao-content"。
发布服务不一定非要使用tomcat,之所以使用tomcat是为了部署方便。

上节课我们一起搭建了内容服务工程,这节课我们一起学习如何添加内容分类。
我们到后台管理页面看看关于内容管理的内容,如下图所示。

我们再来看下content-category.jsp页面,这个页面就是内容分类页面,页面中

  • 用来展示内容分类树,$(function()是在页面加载完后要调用的js,下面这段代码是用来获取分类列表数据的,发起的url请求是/content/category/list,animate:true的意思是设置动画,如果设置为true,展开树形结构时是慢慢展开的效果。如果设置为false展开树形结构就一下子展开了。method:"GET"指定发起的是GET请求。
    请求的url:/content/category/list
    请求的参数:id,当前节点的id。第一次请求是没有参数,需要给默认值“0”
    响应数据:List(@ResponseBody)
    Json数据。
    [{id:1,text:节点名称,state:open(closed)},
    {id:2,text:节点名称2,state:open(closed)},
    {id:3,text:节点名称3,state:open(closed)}]
    业务逻辑:
    1、取查询参数id,parentId
    2、根据parentId查询tb_content_category,查询子节点列表。
    3、得到List
    4、把列表转换成List

在com.taotao.content.service包下新建接口类ContentCategoryService.java,在接口类中添加一个接口getContentCategoryList。 返回值是EasyUITreeNode的集合,EasyUITreeNode类的内容如下所示。id是树节点的id,text是节点的名称,state是指树形是闭合的还是打开的,如果当前节点还有子节点,那么state的值是"closed",如果当前节点已经是叶子节点了,那么state的值是"open"。
taotao-content-interface/src/main/java/com/taotao/content/service/ContentCategoryService.java
taotao-content-service/src/main/java/com/taotao/content/service/impl/ContentCategoryServiceImpl.java
创建一个查询类\设置查询条件\查询\将categoryList转换为List
下面我们发布一下该服务的这个接口,我们在taotao-content-service工程的spring目录下的applicationContext-service.xml文件中发布<dubbo:service interface=“com.taotao.content.service.ContentCategoryService” ref=“ContentCategoryServiceImpl” timeout=“300000”/>

下面我们需要在taotao-manager-web工程添加Controller类来实现内容分类展示,前提是我们需要在pom.xml先添加对taotao-content-interface的依赖。

接着我们需要在taotao-manager-web的springmvc.xml中添加对ContentCategoryService的引用,添加的内容:<dubbo:reference interface=“com.taotao.content.service.ContentCategoryService” id=“contentCategoryService” />
taotao-manager-web/src/main/java/com/taotao/controller/ContentCategoryController.java
下面我们在ContentCategoryController类中调用服务接口。@RequestMapping("/content/category/list")的url是从content-category.jsp当中粘贴过来的。这里需要注意的是,第一次查询内容分类的时候没有参数的,因此需要指定一个默认值0,后续点击要展开某个节点的话,就会把节点id传过来了。还有就是参数parentId与id名称不一致,因此需要@RequestParam(name=“id”,defaultValue=“0”)这样来把id的值赋值给"parentId"。

由于查询内容分类列表涉及到了两个服务和taotao-manager-web,因此需要启动taotao-manager服务和taotao-content服务和taotao-manager-web。
在启动之前先打包taotao-manager和taotao-content到本地maven仓库,然后依次启动taotao-manager和taotao-content,然后是taotao-manager-web,启动好之后我们访问后台,如下图所示,发现可以正常显示内容分类列表了。

分类列表展示出来了,我们下面要做的便是管理内容分类,比如增加、重命名、删除等操作,这些操作可以在某个节点上右键,在右键菜单中操作(当然,现在还没有实现这三个功能)。
右键菜单是在content-category.jsp页面的一个

中定义的,如下图所示。onContextMenu: function(e,node){这行代码的意思是当我们鼠标点击右键的时候触发该js方法,方法的参数中"e"代表事件,node代表鼠标在哪个节点上。e.preventDefault();代表事件传递, ( t h i s ) . t r e e ( ′ s e l e c t ′ , n o d e . t a r g e t ) ; 这 行 代 码 的 意 思 是 (this).tree(&#x27;select&#x27;,node.target);这行代码的意思是 (this).tree(select,node.target);(this)指定鼠标所在的节点转变为jquery对象,.tree(‘select’,node.target);意思是选中这个节点(node这行会添加背景颜色)。$(’#contentCategoryMenu’).menu(‘show’,{这行代码的意思是让右键菜单显示出来,下面的left和top是指坐标。

对节点进行操作的流程是,当我们点击右键菜单中的任何一个操作的时候,data-options=“onClick:menuHandler"告诉我们它会触发menuHandler方法。function menuHandler(item)这行代码的意思是定义menuHandler方法,参数item是指右键菜单这个对象,下面通过item.name来判断用户选择的是哪个操作。var tree = KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲contentCategory….post(”/content/category/delete/",{parentId:node.parentId,id:node.id},function(){这行代码的意思便是去发起url为"/content/category/delete/"的请求,传递的参数是父级id和要删除的节点的id。function()是指回调函数,tree.tree(“remove”,node.target);意思就是从树形结构中删掉这个节点。

那么,实际进行添加节点到数据库的操作是在哪儿控制的呢?如下图所示,onAfterEdit : function(node){意思很明显了,就是我们编辑完之后鼠标离开编辑节点后触发的事件,参数node是指新建的节点,var _tree = KaTeX parse error: Expected '}', got 'EOF' at end of input: …0,因此会进入这个if当中),.post("/content/category/create"的意思是添加节点会去请求"/content/category/create"这个url。{parentId:node.parentId,name:node.text}是指传递的参数有两个,分别是父级id和节点的名称。function(data)是回调函数,data是返回的对象。if(data.status == 200){很显然是指操作成功。_tree.tree(“update”,{target : node.target,id : data.data.id});的意思是如果操作成功了,那么就要去更新一下新添加的节点的id,data.data.id是指添加到数据库中的节点的Id。如果if(node.id == 0)条件不成立,说明不是添加新节点操作,而是更新节点操作。$.post("/content/category/update",{id:node.id,name:node.text});意思是请求url为"/content/category/update",传递的参数有节点id、节点名称。
分析完了js代码,下面我们便来一一实现内容分类的添加、修改、删除功能

首先是添加功能,由于都是单表操作,因此使用逆向工程生成的代码就可以满足要求,我们直接修改服务层即可,我们到taotao-content-interface工程的接口ContentCategoryService.java->addContentaCategory。

下面我们到taotao-content-service工程中去实现这个接口,不过在此之前,由于逆向工程自动生成的insert方法不会自动帮我们给主键的值赋值,因此我们需要在mapper.xml文件中新增一段sql,id取值为"saveAndGetId",这段sql的意思是保存内容分类并且自动给对象的id属性赋值,之所以这样做是因为我们需要用到这个id给树形结构中新增加的节点id赋值,就是给新添加的对象的主键赋值的。
请求的url:/content/category/create
请求的参数:
Long parentId
String name
响应的结果:
json数据,TaotaoResult,其中包含一个对象,对象有id属性,新生产的内容分类id
插入数据结点之后需要判断,如果在原结点是叶子节点的时候添加,更新其父节点(is_parent属性设置为1)
业务逻辑:
1、接收两个参数:parentId、name
2、向tb_content_category表中插入数据。
a) 创建一个TbContentCategory对象
b) 补全TbContentCategory对象的属性
c) 向tb_content_category表中插入数据
3、判断父节点的isparent是否为true,不是true需要改为true。
4、需要主键返回。
5、返回TaotaoResult,其中包装TbContentCategory对象

我们需要到TbContentCategoryMapper类中添加对应的方法。

服务层写完后,我们再写Controller层,我们到taotao-manager-web工程的ContentCategoryController.java当中添加Controller方法
由于taotao-manager-dao工程和taotao-content工程都做了修改,因此我们重新打包taotao-manager-dao和taotao-content工程,然后重启taotao-manager、taotao-content和taotao-manager-web工程。重启后,我们到后台管理系统去增加两个分类

做完了内容分类添加,下面我们实现以下内容分类修改和删除,其中我们需要先修改下content-category.jsp页面的删除请求的参数,因为树形结构的节点只有id、name、sate三个属性,并没有parentId属性,只有新增的节点给parentId赋值了,对于页面刚加载完的树形目录,节点是没有parentId属性的,因此我们把parentId这个参数去掉,我们只通过节点id便可以删除节点了。删除parentId参数后变为"$.post("/content/category/delete/",{id:node.id},function(){"
下面我们到taotao-content-interface添加两个接口,分别是修改分类和删除分类接口
我们到taotao-content-service来实现这两个接口
请求的url:/content/category/delete/
参数:id,当前节点的id。
响应的数据:json。TaotaoResult。
业务逻辑:
1、根据id删除记录。
2、判断父节点下是否还有子节点,如果没有需要把父节点的isparent改为false
3、如果删除的是父节点,子节点要级联删除。
两种解决方案:
1)如果判断是父节点不允许删除。
2)递归删除。(不会推荐使用)

我们到ContentCategoryController暴露两个接口

b) 内容管理
1、内容列表查询
2、新增内容
3、编辑内容
4、删除内容
第一部分:查询内容列表
首先,我们先来看看内容管理后台页面,如下图所示,可以看到页面分两部分,分为左侧内容分类和右侧内容列表两个部分。
为什么内容管理页面左侧的内容分类树形列表直接就是好的呢?我们看看代码就知道了,我们访问的入口是index.jsp页面,这个页面有"内容管理"模块,当我们点击内容管理时,就会去请求content.jsp页面。
我们看看content.jsp页面代码,如下图所示,可以看到上面那个div就是展示我们的内容分类列表的,发起的请求跟我们上节课所说的请求完全一样,因此这里不用我们做任何处理就已经可以使用了。下面的div就是页面的右部分,用来显示内容列表,页面加载的时候,会发起url:’/content/query/list’,queryParams:{categoryId:0}这样的请求,这个内请求会去查询所有内容分类下的所有内容。内容列表的展示其实跟商品列表的展示及其相似,大家可以参考http://blog.csdn.net/u012453843/article/details/67644458这篇博客进行学习。不同的地方是内容列表要根据左边树形节点的Id的变化而变化。

那么内容列表是如何跟左边的内容分类联系起来的呢?我们看下面的js代码,如下图所示,$(function(){});函数是在页面加载完之后触发执行的js代码,var tree = $("#contentCategoryTree");显然是获取内容分类树,var datagrid = $("#contentList");是获取内容列表,onClick : function(node){if(tree.tree(“isLeaf”,node.target)){datagrid.datagrid(‘reload’, {categoryId :node.id});}}这段代码的意思是当我们点击左边内容分类树的某个节点时,会做下判断,判断是不是叶子节点,如果是叶子节点那么就给categoryId赋值为这个叶子节点的id并且会重新加载内容列表,也就意味着重新发起url:’/content/query/list’请求,只是这时的参数queryParams:中categoryId的值变成了单个叶子节点的id。

搞清了内容列表的展示原理后,我们现在就实现内容列表的展示功能
首先在taotao-content-interface工程新增一个接口类ContentService,在接口类中添加一个获取内容列表的接口(EasyUIDataGridResult getContentList(long categoryId,int page,int rows);),如下图所示。
接着在taotao-content-service工程新建一个内容实现类ContentServiceImpl,并在该实现类中实现获取内容列表接口
下面到Controller层去调用服务层接口并返回结果给前台页面
发布服务接口和引用接口,我们先在taotao-content-service工程发布dubbo服务
到taotao-manager-web后台工程引用dubbo发布的内容服务
现在我们开始测试,对taotao-content工程进行重新打包,然后重启taotao-content工程和taotao-manager-web工程,重启后我们访问内容列表

出现错误:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘contentCategoryController’: Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.taotao.content.service.ContentCategoryService com.taotao.controller.ContentCategoryController.contentCategoryService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘contentCategoryService’: FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: Failed to check the status of the service com.taotao.content.service.ContentCategoryService. No provider available for the service com.taotao.content.service.ContentCategoryService from the url zookeeper://192.168.173.148:2181/com.alibaba.dubbo.registry.RegistryService?application=taotao-manager-web&dubbo=2.5.3&interface=com.taotao.content.service.ContentCategoryService&methods=addContentCategory,updateContentCategory,deleteContentCategory,getContentCategoryList&pid=19337&revision=0.0.1-SNAPSHOT&side=consumer&timestamp=1567045238006 to the consumer 192.168.173.1 use dubbo version 2.5.3
由以上的错误的代码可以看到,我们出现此类bug的原因:找到不到对应的bean,bean注入失败。
注入失败的原因主要有:
1.没有添加注解。例如:@Service @Autowared @Controller
2.错误的注入方法
3.对于web.xml中监听器的xml配置错误。
所以我们要解决此问题,主要检查注解正确的添加,包引入是否正确,以及检查web.xml监听器的配置。

错误:
Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named ‘__frch_criterion_1’ in ‘class com.taotao.pojo.TbContentExample’
这个原因是因为PageHelper不支持逆向工程创造出来的条件查询,如果需要实现你的这一目标,你可以在Mapper.xml中自己写一个方法,实现这个逻辑功能。

解决方法:
用mybatis插件自动生成的example查询分页,不带条件时可以成功,带条件会报错There is no getter for property named ‘__frch_criterion_1’ in 'class xxx。
这应该是mybatis的一个Bug。
解决方法:
在mapper接口文件中在方法参数前加上@Param(“example”)
List selectByExampleWithBLOBs(@Param(“example”) TbContentExample example);
List selectByExample(@Param(“example”) TbContentExample example);
然后在mapper.xml文件中and ${criterion.condition}前加上example
最后在查询语句中 ,改为 ,

严重: Servlet.service() for servlet [taotao-manager-web] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter ‘oredCriteria’ not found. Available parameters are [param1, example]
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter ‘oredCriteria’ not found. Available parameters are [param1, example]
解决不了
所以还是回去好好的去下载pageinter-fix jar包吧
下面有一个类似的错误的解决方法:
Parameter ‘id’ not found. Available parameters are [arg2, arg1, arg0, param3, param1]
错误信息:
Parameter ‘id’ not found. Available parameters are [arg2, arg1, arg0, param3, param1, param2]或者Parameter ‘0’ not found. Available parameters are [arg2, arg1, arg0, param3, param1, param2]
这个问题涉及到MyBatis3在使用select节点查询时传递多个参数的问题。问题分析如下:
1、如果是单个查询一般是这样配置:
public List

getUserArticles(int id);

  1.  <select id="getUserArticles" parameterType="int" resultMap="resultUserArticleList">
    
  2.      select user.id,user.userName,user.userAddress,article.id as aid,article.title,article.content from user,article where user.id=article.userid and user.id=#{id}
    
  3.  </select>
    

2、如果使用了多个参数之后,我们一般是这样配置:
public List

getUserArticlesByLimit(int id,int start,int limit);

  1.  <select id="getUserArticlesByLimit" parameterType="int" resultMap="resultUserArticleList">
    
  2.      select user.id,user.userName,user.userAddress,article.id as aid,article.title,article.content from user,article where user.id=article.userid and user.id=#{id} limit #{start},#{limit}
    
  3.  </select>
    

而以上写法有两个错误的地方,第一个是parameterType是要去掉的,虽然这里的参数全部都是int类型,如果涉及多个类型那就必须去掉;第二个是#{id}…及后面的参数写法也是错误的,因为在MyBatis3中不会识别这样的参数,所以应该改成#{arg0},{arg1}这样的形式。
所以,修改后的配置如下:

  1.      select user.id,user.userName,user.userAddress,article.id as aid,article.title,article.content from user,article where user.id=article.userid and user.id=#{arg0} limit #{arg1},#{arg2}
    

通过以上修改完后,错误解决。
2、 当然,这个涉及到了MyBatis3的多参数查询方法,还有很多解决方法,比如使用HashMap类型、对参数进行@Param注解、使用对象传输等的参数进行装载,

最后解决的方法是把pagehelper-fix给下载下来替换掉从中央仓库中下载。
第二部分:添加内容
我们还是从页面代码说起,添加内容是在content.jsp当中定义的,我们可以看到内容列表有"toolbar:contentListToolbar"这么一句代码,这句代码的意思是定义了工具栏,工具栏中有多个功能。
我们来看看工具栏代码,里面有新增、编辑、删除三个操作,我们先看新增内容,text指定我们看到的图标后面的文字,iconCls指定新增图标,handler:function()则是当我们点击"新增"按钮时触发的函数,var node = KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲contentCategory…("#contentCategoryTree").tree(“isLeaf”,node.target)){的意思是如果没有选中的不是节点或者该节点不是叶子节点,那么就弹出提示"新增内容必须选择一个内容分类!"。如果点击的是叶子节点的话,就会调用common.js当中定义的TT的createWindow方法初始化一个弹出框,弹出框中显示的页面是参数指定的url: “/content-add”,也就是content-add.jsp页面。

下面我们便来看下content-add.jsp页面,如下图所示,表格中的字段名称与我们的数据库中表的字段是一致的,这样我们便可以直接使用逆向工程生成的代码了。当页面加载完之后,会触发KaTeX parse error: Expected 'EOF', got '#' at position 51: ….createEditor("#̲contentAddForm …("#contentAddForm [name=categoryId]").val(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲contentCategory…(’#contentAddForm’).form(‘validate’)){的意思是如果表单输入的不合法那么会提示"表单还未填写完!"。contentAddEditor.sync();的意思是如果表单填写合法,那么富文本编辑器将与表单中的隐藏域字段进行内容同步。 . p o s t ( &quot; / c o n t e n t / s a v e &quot; ) 的 意 思 是 发 起 u r l 为 / c o n t e n t / s a v e 的 请 求 , .post(&quot;/content/save&quot;)的意思是发起url为/content/save的请求, .post("/content/save")url/content/save("#contentAddForm").serialize()将表单中的数据序列化为key-value形式的字符串,function(data)是指回调函数。if(data.status == 200){意思是如果返回的状态为200的话说明添加成功了,KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲contentList").d…(’#contentAddForm’).form(‘reset’);的意思是将刚才表单中输入的内容清空。

分析了代码,下面我们来实现添加内容功能
首先是在ContentService接口类添加一个接口TaotaoResult addContent(TbContent content);
接着我们到ContentServiceImpl中去实现这个接口,如下图所示。
由于ContentService服务我们已经在dubbo中发布过了,而且taotao-manager-web工程也引用了,下面我们需要做的便是实现Controller层
修改完之后,我们重新打包taotao-content工程,打包后重启taotao-content工程和taotao-manager-web工程,然后去添加一个内容,添加界面如下图所示。

点击"提交"之后,我们便发现在小广告这个分类下的内容列表中便有了我们刚才添加的内容,如下图所示。

第三部分:修改和删除内容
从content.jsp页面说起,当我们点击"编辑"按钮后会触发handler:function()这个方法,var ids = TT.getSelectionsIds("#contentList");的意思是获取内容列表的所有id的集合。if(ids.length == 0){$.messager.alert(‘提示’,‘必须选择一个内容才能编辑!’);return ;}的意思是如果没有选择任何内容便弹出警告。if(ids.indexOf(’,’) > 0){的意思是如果选择的内容多于一个的话也弹出警告。TT.createWindow({的意思是初始一个弹出窗口。url : "/content-edit"的意思是在弹出框中加载的是content-edit.jsp页面。onLoad : function()里面的内容都是初始化编辑界面的数据。
我们再看看TT.createWindow,如下所示。这段js有个问题就是会让上面的TT.createWindow执行两遍,因此我们需要修改下上面TT.createWindow这段代码。

修改后的内如如下,使用了一个临时变量来记录调用次数,如果是第二次调用的话,则直接返回,不做下面的操作。另外修改的地方是添加一个get请求,根据ID去查询这条内容的全部信息。

那么为何var node = $("#contentList").datagrid(“getSelections”)[0];这句代码就获取到了内容对象还要再通过id去获取内容对象呢?这是因为列表查询的时候就没有查询content字段,也就是富文本编辑框中的内容,我们可以点击编辑,就会发现富文本编辑框是空的,并没有我们添加内容时添加的内容。其实我们可以从获取列表的实现接口中
List list = contentMapper.selectByExample(example);这段代码去查找端倪,既然是调用的selectByExample这个方法,我们便去Mybatis的contentMapper.xml文件当中去看下sql语句。如下所示,可以看到要查询的字段在Base_Column_List当中。

select distinct from tb_content order by ${orderByClause} 我们再看看Base_Column_List当中的字段,发现并没有content字段,这么做的好处是我们在查询内容列表的时候由于并不需要显示内容,而内容可能是非常庞大的,如果把内容字段也一并查询出来的话,那么必定是很消耗性能。因此默认采取了不查询内容字段的方式进行查询。 id, category_id, title, sub_title, title_desc, url, pic, pic2, created, updated 内容字段所在的集合是Blob_Column_List content 我们最好是在要查询某一条内容的时候再去查询content这个字段,而我们的selectByPrimaryKey方法便查询了包括content字段在内的所有字段的内容。如下所示。 select , from tb_content where id = #{id,jdbcType=BIGINT} 也就是说,我们默认的内容列表中的每条记录都是没有content这个字段的内容的,因此我们需要在用户点击编辑按钮的时候根据内容ID去查询这个内容的所有信息,这也是为何在TT.createWindow当中添加$.get("/content/getContent",params, function(data){这么一个请求的原因。 在taotao-content-interface当中添加//获取单个内容信息TaotaoResult getContent(long id);这么一个接口,在taotao-content-service当中添加这个接口的实现,如下所示。 接着就是到taotao-manager-web工程添加暴露的接口

然后我们看下content-edit.jsp页面,表格中的字段与数据库中Tbcontent表是一致的,下面的js代码跟内容添加很相似,页面加载完之后初始化富文本编辑器,并且设置成单图片上传。点提交后先检查表单的内容是否合法,如果不合法则弹出警告。如果合法,那么用富文本编辑器的数据会与表单中的字段值进行同步,然后发起url为/rest/content/edit的请求,将表单中的数据序列化为key-value形式的字符串。在回调函数中判断操作是否成功,如果操作成功那么重新加载内容列表然后关闭弹出窗口。
至于删除的js就更容易理解了,这里就不啰嗦了。现在我们开始写修改和删除内容功能。
先看接口,修改内容和删除内容如下。
下面我们再看下Controller层
做好以上工作后,我们重新打包taotao-content工程,然后重启taotao-content和taotao-manager-web工程。然后我们选择任何一个内容,点击"编辑"去查看富文本编辑框中的内容是否有值,如下图所示,发现没有问题了。

4、首页的轮播图展示实现
上节课我们一起学习了内容的添加、修改、删除,这节我们一起学习下如何展示首页大广告位。
首先,看一下页面代码,如下图所示,首页大广告是采用轮播图的方式显示的。数据需要从后台动态获取,它是从"ad1"这么一个变量中去取值的,因此我们在Controller层返回的结果中动态数据所对应的变量名一定要是"ad1"。

下面在taotao-content-interface工程的ContentService接口类中添加一个接口
接着我们去taotao-content-service工程的ContentServiceImpl类中去实现这个接口
由于前台工程taotao-portal-web需要使用taotao-content-interface工程,那么就在pom.xml文件当中添加如下依赖。

下面我们来看下后台需要返回的数据格式是什么,如下所示,可以看到用到的字段有"srcB"、“height”、“alt”、“width”、“src”、“widthB”、“href”、"heightB"八个。这些字段与数据库表中的字段有不一致的地方,通常处理的方式是建一个POJO类来专门接收从数据库查询到的数据及自定义的配置然后转换成json格式的字符串。
那么我们下面便来新建一个taotao.taotao.portal.pojo包并在包下新建一个AD1Node类
下面我们在taotao-portal-web工程引用dubbo发布的ContentService服务<dubbo:reference interface=“com.taotao.content.service.ContentService” id=“contentService” />
实现Controller层代码
可以看到Controller层有很多变量都是从配置文件中去获取的,配置文件(resource.properties)
好了,代码写完后,我们重新打包taotao-content工程,打包完之后重启taotao-content工程,然后启动taotao-portal-web工程。如下图所示,可以看到下面4个数字图标,只是没有图片,这是因为数据库中的图片地址不正确而已。我们可以删掉原来的数据,重新添加几条数据。
下面再到首页去观察,如下图所示,发现轮播图已经好了。
总结轮播图:
taotao-portal-web工程中,动态展示内容信息。
前端团队:负责JS,html等开发。
后端团队:负责后台的开发并提供数据给前端。
只需要动态生成一个json数据,轮播图就可以动taotao-portal-web工程下的index.jsp中:
分析:
portal-web 需要 自己自定义的POJO 的类型数据的列表
content 服务层 公用的,可以被其他的系统(表现的系统)来调用 ;
为了通用性:content 服务层中 获取 tbcontent的内容列表 即:list
portal-web 表现层 需要拿到tbcontent 的列表,然后进行转换成自定义的类型的数据列表即可。
从tb_content表中取数据,根据(叶子节点)内容分类id查询列表(内容列表)。
内容分类id固定,需要配置在属性文件中。
List
图片的width、height配置在属性文件中。
Alt属性从sub_title中取。
Src->pic
srcB->pic2
Href->url
分析:
URL:/index
参数:无。
返回值:首页页面 (数据是JSON 设置model中)
业务逻辑:
1.根据分类的id 查询 内容列表(List)
2.发布服务
3.表现层引入服务
4.调用服务 ,转换成自定义的数据类型(Ad1Node) 的列表
5.将数据列表设置到Model 中,返回给页面。
需要创建一个pojo转换成页面需要的json数据格式。放入com.taotao.portal.pojo中。
如果很多人访问页面,就会不断地从数据库中获取图片,就对数据库造成很大压力,这时候我们使用缓存redis

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值