一 课程计划
首页大广告位的实现。
cms系统的实现:在后台管理内容及内容分类的系统就叫做cms系统。
发布服务
调用服务展示内容
二 首页大广告位实现
首页的内容需要动态管理,需要后台管理功能。
抽取首页展示内容的共性:
- 有一张图片
- 有一个链接
- 有一个标题
- 有链接的提示
- 价格
需要把内容进行分类,分类应该是一个树形结构。
在展示首页时,可以根据分类取内容信息,把内容展示到页面。
在后台管理内容及内容分类的系统就叫做cms系统。
三 CMS系统(内容管理系统)
需要先实现内容的分类管理,再实现内容管理。
3.1、内容分类管理
3.1.1、需求分析
初始化树形视图的
url:/content/category/list
参数是id,当前节点id属性,应该根据此id查询子节点列表。
返回值:包含id、text、state三个属性的json数据列表
3.1.2、Dao层
表结构:
Sql语句:
根据parentid查询节点列表
SELECT * FROM `tb_content_category` WHERE parent_id = 30;
单表查询可以实现逆向工程生成的代码。
3.1.3、Service层
功能:接收parentid。根据parentid查询节点列表,返回返回一个EasyUI异步Tree要求的节点列表。每个节点包含三个属性id、text、state三个属性。可以使用EUTreeNode实体类。
参数:id
返回值:List<EUTreeNode>
package com.taotao.service.impl;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import com.taotao.mapper.TbContentCategoryMapper;
import com.taotao.pojo.EUTreeNode;
import com.taotao.pojo.TbContentCategory;
import com.taotao.pojo.TbContentCategoryExample;
import com.taotao.pojo.TbContentCategoryExample.Criteria;
import com.taotao.service.ContentCategoryService;
@Service
public class ContentCategoryServiceImpl implements ContentCategoryService {
//关联dao
@Resource
private TbContentCategoryMapper contentCategoryMapper ;
/*
* 功能:接收parentid。根据parentid查询节点列表,返回返回一个EasyUI异步Tree要求的节点列表。
* 每个节点包含三个属性id、text、state三个属性。可以使用EUTreeNode实体类。
* 参数:id 返回值:List<EUTreeNode>
*/
@Override
public List<EUTreeNode> getCategoryList(Long parentid) {
//根据parentid 查询节点列表
TbContentCategoryExample example = new TbContentCategoryExample();
Criteria criteria = example.createCriteria();
//设置条件
criteria.andParentIdEqualTo(parentid);
//执行查询
List<TbContentCategory> list = contentCategoryMapper.selectByExample(example);
//创建目录树
ArrayList<EUTreeNode> resultList = new ArrayList<>();
//遍历
for (TbContentCategory tbContentCategory : list) {
//创建一个TreeNode对象
/*
* EUTreeNode node = new EUTreeNode(); node.setId(tbContentCategory.getId());
* node.setText(tbContentCategory.getName());
* node.setState(tbContentCategory.getIsParent()?"closed":"open");
*/
EUTreeNode node = new EUTreeNode(tbContentCategory.getId(),tbContentCategory.getName(),tbContentCategory.getIsParent()?"closed":"open");
resultList.add(node);
}
return resultList;
}
}
3.1.4、Controller层
接收页面传递过来的parentid,根据parentid查询节点列表。返回List<EUTreeNode>。需要响应json数据。
package com.taotao.controller;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.taotao.pojo.EUTreeNode;
import com.taotao.service.ContentCategoryService;
@Controller
@RequestMapping("/content/category/")
public class ContentCategoryController {
@Resource
private ContentCategoryService contentCategoryService ;
@RequestMapping("/list")
@ResponseBody
public List<EUTreeNode> getCategoryList(@RequestParam(value="id",defaultValue="0")Long parentId){
return contentCategoryService.getCategoryList(parentId);
}
}
3.1.5 效果图
3.2、添加内容分类
3.2.1、需求分析
请求的url:/content/category/create
参数:
1、parentId父节点id
2、name:当前节点的名称
返回值:TaotaoResult。其中包含节点pojo对象。
3.2.2、Dao层
可以使用逆向工程的代码
3.2.3、Service层
功能:接收两个参数parentId父节点id、name:当前节点的名称。向tb_content_category表中添加一条记录。返回TaoTaoResult包含记录的pojo对象。
需要返回主键信息:
需要修改mapper文件,返回主键信息。
/*
* 二 添加内容分类
* 功能:接收两个参数parentId父节点id、 name:当前节点的名称。
* 向tb_content_category表中添加一条记录。返回TaoTaoResult包含记录的pojo对象。
* 需要返回主键信息: 需要修改mapper文件,返回主键信息。
*
*/
@Override
public TaotaoResult insertContentCategory(Long parentId, String name) {
//创建一个pojo
//设置内容分类表中的信息
TbContentCategory contentCategory = new TbContentCategory();
contentCategory.setIsParent(false);//'该类目是否为父类目,1为true,0为false',
contentCategory.setName(name);
contentCategory.setStatus(1); // '状态。可选值:1(正常),2(删除)',
contentCategory.setParentId(parentId);
contentCategory.setSortOrder(1);//'排列序号,表示同级类目的展现次序,如数值相等,则按名称次序排列
contentCategory.setCreated(new Date());
contentCategory.setUpdated(new Date());
//将补全后的数据插入到数据库
contentCategoryMapper.insert(contentCategory);
//int insert = contentCategoryMapper.insert(contentCategory);
//System.out.println("---------------------"+insert);
//查看父节点的isParent列是否为true,如果不是的话改为true
TbContentCategory parentCat = contentCategoryMapper.selectByPrimaryKey(parentId);
//判断是否为true
if (!parentCat.getIsParent()) {
parentCat.setIsParent(true);
//更新父节点
contentCategoryMapper.updateByPrimaryKey(parentCat);
}
return TaotaoResult.ok(contentCategory.getId());//返回主键信息
}
3.2.4、Controller层
接收两个参数parentid、name。调用Service添加记录。返回TaotaoResult。应该返回json数据。
/*
* 添加内容分类
* 接收两个参数parentid、name。调用Service添加记录。返回TaotaoResult。应该返回json数据。
*/
@RequestMapping("create")
public TaotaoResult insertContentCategory(Long parentId,String name) {
TaotaoResult result=contentCategoryService.insertContentCategory(parentId, name);
return result;
}
3.2.5 效果
3.3、删除
3.3.1、分析
需求分析:
请求的url:/content/category/delete/
参数:
1 parentId
2 Id
返回值:没有返回值,随便返回一个即可。TaotaoResult
业务逻辑:
接收parentid、id两个参数。删除id对应的记录。需要判断parentid对应的记录下是否有子节点。如果没有子节点。需要把parentid对应的记录的isparent改成false。
注意:删除,直接是物理删除。
3.4、重名名节点
1、使节点变为可编辑状态
2、当编辑完成后会触发onAfterEdit事件
请求的url:/content/category/update
参数:id、name
返回值:没有返回值,可以返回TaotaoResult。Json格式
业务逻辑:根据id更新记录的name列即可
3.2、内容管理
内容管理表:
3.2.1、内容列表
需求分析
请求url:/content/query/list
参数:page、rows、categoryId
返回值:
EUDataGridResult
Total、rows:内容pojo列表。
业务逻辑:
根据内容分类id查询内容列表。需要实现分页。返回EUDataGridResult
3.2.2、内容添加
分析
图片上传初始化:
内容表单提交:
请求的url:/content/save
请求的方法:post
请求内容:表单中的内容。
返回的结果:TaotaoResult。
3.2.3、Dao层
向tb_content表中插入数据,使用逆向工程代码
3.2.4、Service层
接收表tb_content对应的pojo对象。把pojo对象插入到tb_content表中。返回TaotaoResult。
package com.taotao.service.impl;
import java.util.Date;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import com.taotao.mapper.TbContentMapper;
import com.taotao.pojo.TaotaoResult;
import com.taotao.pojo.TbContent;
import com.taotao.service.ContentService;
@Service
public class ContentServiceImpl implements ContentService {
@Resource
private TbContentMapper contentMapper;
/*
* 内容添加:
* 接收表tb_content对应的pojo对象。把pojo对象插入到tb_content表中。返回TaotaoResult。
* ( 接收tb_content对象调用Mapper,补全实体类需要的数据 向tb_content表中添加数据,返回TaoTaoResult)
*/
@Override
public TaotaoResult insertContent(TbContent content) {
//补全pojo内容
content.setCreated(new Date());
content.setUpdated(new Date());
//将修改后的数据插入到数据库
contentMapper.insert(content);
return TaotaoResult.ok();
}
}
3.2.5、Controller层
接收表单中的内容,使用pojo接收。要求pojo的属性要和表单中的name一致。调用Service插入内容信息。返回TaotaoResult。Json格式的数据。
package com.taotao.controller;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.taotao.pojo.TaotaoResult;
import com.taotao.pojo.TbContent;
import com.taotao.service.ContentService;
@Controller
@RequestMapping("/content")
public class ContentController {
@Resource
private ContentService contentService;
/*
* 添加内容
* 接收表单中的内容,使用pojo接收。要求pojo的属性要和表单中的name一致
* 。调用Service插入内容信息。返回TaotaoResult。Json格式的数据。
*
*/
@RequestMapping("/save")
@ResponseBody
public TaotaoResult insertContent(TbContent content) {
return contentService.insertContent(content);
}
}
3.2.6 效果展示
先开启nginx,才能进行http服务,在游览器上上传访问图片
四 展示首页大广告位
4.1、首页大广告位方案
4.1.1、方案一
jsonp跨域请求
需要当首页加载完毕后,大广告位就应该显示。没有触发事件。不是太合适。
优点:不需要二次请求,页面直接加载内容数据。减少门户系统的压力。
缺点:需要延迟加载。不利于seo优化。
4.1.2、方案二(我们使用的方法)
优点:有利于seo优化。可以在taotao-portal中对数据进行加工。
缺点:系统直接需要调用服务查询内容信息。多了一次http请求。
系统直接服务的调用,需要使用 httpclient(系统之间进行交互)来实现。Taotao-portal和taotao-rest是在同一个局域网内部。速度非常快,调用时间可以忽略不计。
展示首页内容功能,使用方案二实现。
4.2、展示流程
4.3、内容服务发布
4.3.1、需求分析
根据内容的分类id查询内容列表,从tb_content表中查询。服务是一个restFul形式的服务。使用http协议传递json格式的数据。
4.3.2、Dao层
从tb_content表中查询,根据内容分类id查询。是单表查询。可以使用逆向工程生成的代码。
4.3.3、Service层
在rest项目中创建
接收内容分类id,根据分类id查询分类列表。返回一个内容pojo列表。
参数:分类id
返回值:pojo列表
package com.taotao.rest.service.impl;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import com.taotao.mapper.TbContentMapper;
import com.taotao.pojo.TbContent;
import com.taotao.pojo.TbContentExample;
import com.taotao.pojo.TbContentExample.Criteria;
import com.taotao.rest.service.ContentService;
@Service
public class ContentServiceImpl implements ContentService {
@Resource
private TbContentMapper contentMapper;
/*
* 查询内容列表:
* 接收内容分类id,根据分类id查询分类列表。返回一个内容pojo列表。
* 参数:分类id 返回值:pojo列表
*/
@Override
public List<TbContent> getContentList(Long contentCid) {
//根据内容分类id查询内容列表
TbContentExample example = new TbContentExample();
//设置条件
Criteria criteria = example.createCriteria();
criteria.andCategoryIdEqualTo(contentCid);
//执行查询
List<TbContent> list = contentMapper.selectByExample(example);
return list;
}
}
4.3.4、Controller层
发布服务。接收查询参数。Restful风格内容分类id应该从url中取。
/rest/content/list/{contentCategoryId}
从url中取内容分类id,调用Service查询内容列表。返回内容列表。返回一个json格式的数据。可以使用TaotaoResult包装此列表。
package com.taotao.rest.controller;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.taotao.pojo.TaotaoResult;
import com.taotao.pojo.TbContent;
import com.taotao.rest.service.ContentService;
import com.taotao.util.ExceptionUtil;
@Controller
@RequestMapping("/content")
public class ContentController {
@Resource
private ContentService contentService;
/*
* 发布服务。接收查询参数。Restful风格内容分类id应该从url中取。
* /rest/content/list/{contentCategoryId}
* 从url中取内容分类id,调用Service查询内容列表。返回内容列表。返回一个json格式的数据。
* 可以使用TaotaoResult包装此列表。
*/
@RequestMapping("/list/{contentCategoryId}")
@ResponseBody
public TaotaoResult getConTentList(@PathVariable Long contentCategoryId) {
try {
List<TbContent> list = contentService.getContentList(contentCategoryId);
return TaotaoResult.ok(list);
} catch (Exception e) {
e.printStackTrace();
return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
}
}
ExceptionUtil 工具类
package com.taotao.util;
import java.io.PrintWriter;
import java.io.StringWriter;
public class ExceptionUtil {
/**
* 获取异常的堆栈信息
*
* @param t
* @return
*/
public static String getStackTrace(Throwable t) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
try {
t.printStackTrace(pw);
return sw.toString();
} finally {
pw.close();
}
}
}
4.3.5、测试
我们可以使用工具测试
http://localhost:8081/rest/content/list/89
4.4、Httpclient的使用
4.4.1、什么是httpclient
HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
下载地址:http://hc.apache.org/
4.4.2、添加依赖
需要把httpclient的jar包添加到工程中。只需要在工程中添加httpclient的依赖。
4.4.3、使用httpclient执行get请求(无参数)
package com.taotao.test;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
public class Test1 {
@Test
public void doGet() throws Exception {
//创建一个httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
//创建一个GET对象
HttpGet get = new HttpGet("http://www.baidu.com");
//执行请求
CloseableHttpResponse response = httpClient.execute(get);
//取响应的结果
int statusCode = response.getStatusLine().getStatusCode();
System.out.println(statusCode);
HttpEntity entity = response.getEntity();
String string = EntityUtils.toString(entity, "utf-8");
System.out.println(string);
//关闭httpclient
response.close();
httpClient.close();
}
}
4.4.4、带参数get请求
package com.taotao.test;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
public class Test2 {
@Test
public void doGetWithParam() throws Exception{
//创建一个httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
//创建一个uri对象
URIBuilder uriBuilder = new URIBuilder("http://www.baidu.com/s");
uriBuilder.addParameter("wd", "苏大强");
HttpGet get = new HttpGet(uriBuilder.build());
//执行请求
CloseableHttpResponse response = httpClient.execute(get);
//取响应的结果
int statusCode = response.getStatusLine().getStatusCode();
System.out.println(statusCode);
HttpEntity entity = response.getEntity();
String string = EntityUtils.toString(entity, "utf-8");
System.out.println(string);
//关闭httpclient
response.close();
httpClient.close();
}
}
4.5、Httpclient封装成工具类
其他项目也可能会用到httpclient,所以把工具类放到taotao-common中。
五 大广告位展示
5.1、需求分析
需要创建一个json字符串传递给jsp:
Json字符串如何传递给jsp:使用modelAndView对象把json字符串传递给jsp。
如何获得json字符串:获得一个广告位对应的内容列表,需要调用taotao-rest的服务。把列表转换成json数据格式要求的pojo对象列表。需要使用httpclient调用taotao-rest的服务。
5.2、Dao层
没有
5.3、Service层
根据内容分类id查询分类的内容列表,需要使用httpclient(系统之间进行交互)调用taotao-rest的服务。得到一个json字符串。
需要把字符串转换成java对象taotaoResult对象。从taotaoResult对象中取data属性,得到内容列表。把内容列表转换成jsp页面要求的json格式。返回一个json字符串。
参数:没有参数
返回值:json字符串。
#ji chu url
REST_BASE_URL=http://localhost:8081/rest
# da guanggao wei url
REST_INDEX_AD_URL=/content/list/89
package com.taotao.portal.service.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.taotao.pojo.TaotaoResult;
import com.taotao.pojo.TbContent;
import com.taotao.portal.service.ContentService;
import com.taotao.util.HttpClientUtil;
import com.taotao.util.JsonUtils;
@Service
public class ContentServiceImpl implements ContentService {
@Value("${REST_BASE_URL}")
private String REST_BASE_URL;
@Value("REST_INDEX_AD_URL")
private String REST_INDEX_AD_URL;
/*大广告位展示
* 根据内容分类id查询分类的内容列表,需要使用httpclient调用taotao-rest的服务。得到一个json字符串。
* 需要把字符串转换成java对象taotaoResult对象。从taotaoResult对象中取data属性,得到内容列表。
* 把内容列表转换成jsp页面要求的json格式。返回一个json字符串。
* 参数:没有参数 返回值:json字符串。
*/
@Override
public String getContentList() {
//调用服务层的服务
String result = HttpClientUtil.doGet(REST_BASE_URL+REST_INDEX_AD_URL);
//把字符串转换为TaotaoResult对象
try {
TaotaoResult taotaoResult = TaotaoResult.formatToList(result,TbContent.class);
//从taotaoResult对象中取data属性,得到内容列表
List<TbContent> list=(List<TbContent>) taotaoResult.getData();
ArrayList<Map> resultList = new ArrayList<>();
// 创建一个jsp页面要求的pojo列表(把内容列表转换成jsp页面要求的json格式。返回一个json字符串。)
for (TbContent tbContent : list) {
Map map = new HashMap<>();
map.put("src", tbContent.getPic());
map.put("height", 240);
map.put("width", 670);
map.put("srcB", tbContent.getPic2());
map.put("widthB", 550);
map.put("heightB", 240);
map.put("href", tbContent.getUrl());
map.put("alt", tbContent.getSubTitle());
resultList.add(map);
}
return JsonUtils.objectToJson(resultList);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
5.4、Controller层
在taotao-portal项目中的IndexController中,展示首页返回一个逻辑视图,需要把首页大广告位的json数据传递给jsp。
package com.taotao.portal.controller;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.taotao.portal.service.ContentService;
@Controller
public class IndexController {
@Resource
private ContentService contentService;
//跳转页面
@RequestMapping("/index")
public String toIndex(Model model) {
String adJson = contentService.getContentList();
model.addAttribute("ad1", adJson);
return "index";
}
}
5.5 截图留念
先去为大广告 添加内容管理
然后访问门户网站
点击图片就可以直接跳转页面(因为内容管理表中有个字段是url)