第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

时间:2023-03-09 14:24:29
第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第五天】

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

开发环境:

Eclipse IDE for Enterprise Java Developers
OS: Windows 10, v.10.0, x86_64 / win32
Java version: 1.8.0_221

06.第六天(CMS系统)


第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

需要把内容进行分类,分类应该是一个树形结构。在展示首页时,可以根据分类取内容信息,把内容展示到页面。

在后台管理内容及内容分类的系统就叫做cms系统。

先实现内容的分类管理再实现内容管理。

3.1    内容分类管理

3.1.1   内容分类初始化

需求分析

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

初始化树形视图的url:/content/category/list

参数是id,当前节点id属性,应该根据此id查询子节点列表。

返回值:包含id、text、state三个属性的json数据列表

Service层

功能:接收parentid。根据parentid查询节点列表,返回返回一个EasyUI异步Tree要求的节点列表。每个节点包含三个属性id、text、state三个属性。可以使用自定义的EUTreeNode。

参数:id

返回值:List<EUTreeNode>

@Service
public class ContentCategoryServiceImpl implements ContentCategoryService { @Autowired
private TbContentCategoryMapper contentCategoryMapper;
@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);
List<EUTreeNode> resultList = new ArrayList<>();
for (TbContentCategory tbContentCategory : list) {
//创建一个节点
EUTreeNode node = new EUTreeNode();
node.setId(tbContentCategory.getId());
node.setText(tbContentCategory.getName());
node.setState(tbContentCategory.getIsParent()?"closed":"open"); resultList.add(node);
}
return resultList;
} }

Controller

接收页面传递过来的parentid,根据parentid查询节点列表。返回List<EUTreeNode>。需要响应json数据。

@Controller
@RequestMapping("/content/category")
public class ContentCategoryController { @Autowired
private ContentCategoryService contentCategoryService; @RequestMapping("/list")
@ResponseBody
public List<EUTreeNode> getContentCatList(@RequestParam(value="id", defaultValue="0")Long parentId) {
List<EUTreeNode> list = contentCategoryService.getCategoryList(parentId);
return list;
}
}

3.1.2   内容分类添加

请求的url:/content/category/create

参数:

1、parentId父节点id

2、name:当前节点的名称

返回值:TaotaoResult。其中包含节点pojo对象。

Service层

功能:接收两个参数parentId父节点id、name:当前节点的名称。向tb_content_category表中添加一条记录。返回TaoTaoResult包含记录的pojo对象。

需要返回主键信息:

需要修改mapper文件,返回主键信息。

  <selectKey keyProperty="id" resultType="Long" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

@Override
public TaotaoResult insertContentCategory(long parentId, String name) { //创建一个pojo
TbContentCategory contentCategory = new TbContentCategory();
contentCategory.setName(name);
contentCategory.setIsParent(false);
//'状态。可选值:1(正常),2(删除)',
contentCategory.setStatus(1);
contentCategory.setParentId(parentId);
contentCategory.setSortOrder(1);
contentCategory.setCreated(new Date());
contentCategory.setUpdated(new Date());
//添加记录
contentCategoryMapper.insert(contentCategory);
//查看父节点的isParent列是否为true,如果不是true改成true
TbContentCategory parentCat = contentCategoryMapper.selectByPrimaryKey(parentId);
//判断是否为true
if(!parentCat.getIsParent()) {
parentCat.setIsParent(true);
//更新父节点
contentCategoryMapper.updateByPrimaryKey(parentCat);
}
//返回结果
return TaotaoResult.ok(contentCategory);
}

Controller层

接收两个参数parentid、name。调用Service添加记录。返回TaotaoResult。应该返回json数据。

@RequestMapping("/create")
@ResponseBody
public TaotaoResult createContentCategory(Long parentId, String name) {
TaotaoResult result = contentCategoryService.insertContentCategory(parentId, name);
return result;
}

3.2  内容管理

内容管理表:

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

3.2.2   内容添加

需求分析:

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

内容表单提交:

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

请求的url:/content/save

请求的方法:post

请求内容:表单中的内容

返回的结果:TaotaoResult

Dao层

向tb_content表中插入数据。可以使用逆向工程生成的代码。

Service层

接收表tb_content对应的pojo对象。把pojo对象插入到tb_content表中。

返回TaotaoResult。

@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();
} }

Controller层

接收表单中的内容,使用pojo接收。要求pojo的属性要和表单中的name一致。调用Service插入内容信息。返回TaotaoResult。Json格式的数据。

@Controller
@RequestMapping("/content")
public class ContentController { @Autowired
private ContentService contentService; @RequestMapping("/save")
@ResponseBody
public TaotaoResult insertContent(TbContent content) {
TaotaoResult result = contentService.insertContent(content);
return result;
}
}

3.2.1   内容列表

需求分析:根据内容分类id查询内容列表。需要实现分页。

请求url:/content/query/list

参数:page、rows、categoryId

返回值类型:EUDataGridResult

Total、rows:内容pojo列表。

    //查询内容列表并分页
@Override
public EUDataGridResult queryContentList(Long categoryId, int page, int rows) {
//使用分页插件处理分页
PageHelper.startPage(page, rows);//使用逆向工程的条件查询
TbContentExample example = new TbContentExample();
Criteria criteria = example.createCriteria();
criteria.andCategoryIdEqualTo(categoryId);
List<TbContent> list = contentMapper.selectByExampleWithBLOBs(example);
//获取分页插件信息
PageInfo<TbContent> pageInfo = new PageInfo<TbContent>(list);
//
EUDataGridResult result = new EUDataGridResult();
result.setTotal(pageInfo.getTotal());
result.setRows(list); return result;
}

Controller层

    @RequestMapping("/query/list")
@ResponseBody
public EUDataGridResult queryContentList(Long categoryId ,int page,int rows) { return contentService.queryContentList(categoryId, page, rows); }

3.2.6 内容的删除

请求url:/content/delete

请求的方法:post

请求参数:ids

返回的结果:TaotaoResult

图片位置:content.jsp

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

Service层

    @Override
//删除内容根据ids
public TaotaoResult deleteContent(Long contentId) {
//创建查询条件
TbContentExample example = new TbContentExample();
TbContentExample.Criteria criteria = example.createCriteria();
criteria.andIdEqualTo(contentId);
//执行删除
contentMapper.deleteByExample(example); return TaotaoResult.ok();
}

Controller层

    //删除选中内容
@RequestMapping("/delete")
@ResponseBody
public TaotaoResult deleteContent(@RequestParam("ids")Long contentId ) {
TaotaoResult result = contentService.deleteContent(contentId); return result; }

3.1.3 内容分类的删除

Controller层

    //内容分类管理:删除
@RequestMapping("/delete")
@ResponseBody
public TaotaoResult deleteContentCategory( Long id ) {
TaotaoResult result = contentCategoryService.deleteContentCategory(id); return result;
}

Service层

    @Autowired
private TbContentCategoryMapper contentCategoryMapper; @Override
public TaotaoResult deleteContentCategory(long id) {
deleteCategoryAndChildNode(id);
return TaotaoResult.ok();
} private List<TbContentCategory> getChildNodeList(Long id) {
//查询所有父节点ID为传入id的内容分类
TbContentCategoryExample example = new TbContentCategoryExample();
TbContentCategoryExample.Criteria criteria = example.createCriteria();
criteria.andParentIdEqualTo(id);
//查询结果作为返回值
return contentCategoryMapper.selectByExample(example);
} // 根据ID删除叶子分类节点和自己的节点并判断父节点属性
private void deleteCategoryAndChildNode(Long id) { TbContentCategory tcc = contentCategoryMapper.selectByPrimaryKey(id);
// 1.删除所有该分类下的子节点
if (tcc.getIsParent()) {
// 查询该节点下的孩子节点
List<TbContentCategory> list = getChildNodeList(id);
// 删除所有孩子节点
for (TbContentCategory contentCategory : list) {
// 递归调用本方法自己
deleteCategoryAndChildNode(contentCategory.getId());
}
}
// 2.判断删除完成后,父节点下是否还有其他子节点
List<TbContentCategory> list = getChildNodeList(tcc.getParentId());
if (CollectionUtils.isEmpty(list)) {
TbContentCategory parentCategory = contentCategoryMapper.selectByPrimaryKey(tcc.getParentId());
parentCategory.setIsParent(false);
contentCategoryMapper.updateByPrimaryKey(parentCategory);
} // 3.删除本节点
contentCategoryMapper.deleteByPrimaryKey(id); return;
}

4.1    首页大广告方案

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

优点:有利于seo优化。可以在taotao-portal中对数据进行加工。

缺点:系统直接需要调用服务查询内容信息。多了一次http请求。

系统直接服务的调用,需要使用httpclient来实现。Taotao-portal和taotao-rest是在同一个局域网内部。速度非常快,调用时间可以忽略不计。

4.2    展示流程

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

4.3    内容服务发布

4.3.1   需求分析

根据内容的分类id查询内容列表,从tb_content表中查询。服务是一个restFul形式的服务。使用http协议传递json格式的数据。

4.3.2   Dao层

从tb_content表中查询,根据内容分类id查询。是单表查询。可以使用逆向工程生成的代码。

4.3.3   Service层

接收内容分类id,根据分类id查询分类列表。返回一个内容pojo列表。

参数:分类id

返回值:pojo列表

taotao-rest工程

/**
* 内容管理
* @author kangy
*
*/
@Service
public class ContentServiceImpl implements ContentService {
@Autowired
private TbContentMapper contentMapper; @Override
public List<TbContent> getContentList(long contentCid) {
// 根据内容分类id查询内容列表
TbContentExample example = new TbContentExample();
TbContentExample.Criteria criteria = example.createCriteria();
criteria.andCategoryIdEqualTo(contentCid);
//执行查询
List<TbContent> list = contentMapper.selectByExampleWithBLOBs(example); //返回结果
return list;
} }

ContentServiceImpl

4.3.4   Controller层

发布服务。接收查询参数。Restful风格内容分类id应该从url中取。

/rest/content/list/{contentCategoryId}

从url中取内容分类id,调用Service查询内容列表。返回内容列表。返回一个json格式的数据。可以使用TaotaoResult包装此列表。

@RestController
@RequestMapping("/content")
public class ContentController { @Autowired
private ContentService contentService; @GetMapping("/list/{contentCategoryId}")
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));
} } }
package com.taotao.common.utils;

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();
}
}
}

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

http://localhost:8081/rest/content/list/89

4.4    Httpclient的使用

4.4.1   什么是httpclient

HttpClient 是 Apache 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
下载地址:

http://hc.apache.org/

4.4.2   添加依赖

需要把httpclient的jar包添加到工程中。只需要在工程中添加httpclient的依赖。

        <!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>

12.httpclient执行get请求

使用httpclient执行get请求

@Test
public void doGet() throws Exception {
//创建一个httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
//创建一个GET对象
HttpGet get = new HttpGet("http://www.sogou.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();
}

执行get请求带参数

@Test
public void doGetWithParam() throws Exception{
//创建一个httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
//创建一个uri对象
URIBuilder uriBuilder = new URIBuilder("http://www.sogou.com/web");
uriBuilder.addParameter("query", "花千骨");
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();
}

使用httpclient执行post请求

@Test
public void doPost() throws Exception {
CloseableHttpClient httpClient = HttpClients.createDefault(); //创建一个post对象
HttpPost post = new HttpPost("http://localhost:8082/httpclient/post.html");
//执行post请求
CloseableHttpResponse response = httpClient.execute(post);
String string = EntityUtils.toString(response.getEntity());
System.out.println(string);
response.close();
httpClient.close(); }

带参数post请求

@Test
public void doPostWithParam() throws Exception{
CloseableHttpClient httpClient = HttpClients.createDefault(); //创建一个post对象
HttpPost post = new HttpPost("http://localhost:8082/httpclient/post.html");
//创建一个Entity。模拟一个表单
List<NameValuePair> kvList = new ArrayList<>();
kvList.add(new BasicNameValuePair("username", "zhangsan"));
kvList.add(new BasicNameValuePair("password", "123")); //包装成一个Entity对象
StringEntity entity = new UrlEncodedFormEntity(kvList, "utf-8");
//设置请求的内容
post.setEntity(entity); //执行post请求
CloseableHttpResponse response = httpClient.execute(post);
String string = EntityUtils.toString(response.getEntity());
System.out.println(string);
response.close();
httpClient.close();
}

4.4.4   Httpclient封装成工具类

其他项目也可能会用到httpclient,所以把工具类放到taotao-common中。

package com.taotao.common.utils;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils; public class HttpClientUtil { public static String doGet(String url, Map<String, String> param) { // 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault(); String resultString = "";
CloseableHttpResponse response = null;
try {
// 创建uri
URIBuilder builder = new URIBuilder(url);
if (param != null) {
for (String key : param.keySet()) {
builder.addParameter(key, param.get(key));
}
}
URI uri = builder.build(); // 创建http GET请求
HttpGet httpGet = new HttpGet(uri); // 执行请求
response = httpclient.execute(httpGet);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
} public static String doGet(String url) {
return doGet(url, null);
} public static String doPost(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建参数列表
if (param != null) {
List<NameValuePair> paramList = new ArrayList<>();
for (String key : param.keySet()) {
paramList.add(new BasicNameValuePair(key, param.get(key)));
}
// 模拟表单
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
httpPost.setEntity(entity);
}
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} return resultString;
} public static String doPost(String url) {
return doPost(url, null);
} public static String doPostJson(String url, String json) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建请求内容
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} return resultString;
}
}

HttpClientUtil

5   大广告位展示

5.1    需求分析

需要创建一个json字符串传递给jsp:

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

Json字符串如何传递给jsp:使用modelAndView对象把json字符串传递给jsp。

如何获得json字符串:获得一个广告位对应的内容列表,需要调用taotao-rest的服务。把列表转换成json数据格式要求的pojo对象列表。

需要使用httpclient调用taotao-rest的服务。

taotao-portal项目子模块

package com.taotao.portal.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import com.taotao.common.pojo.TaotaoResult;
import com.taotao.common.utils.HttpClientUtil;
import com.taotao.common.utils.JsonUtils;
import com.taotao.pojo.TbContent;
import com.taotao.portal.service.ContentService; /**
* 调用服务层服务,查询内容列表
*
* @author kangy
*
*/
@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; @Override
public String getContentlist() {
// 调用服务层服务
String result = HttpClientUtil.doGet(REST_BASE_URL + REST_INDEX_AD_URL);
// 把字符串转换成TaotaoResult
try {
TaotaoResult taotaoResult = TaotaoResult.formatToList(result, TbContent.class);
// 取内容列表
List<TbContent> list = (List<TbContent>) taotaoResult.getData();
List<Map> resultList = new ArrayList<Map>();
// 创建一个jsp页码要求的pojo列表
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("height", 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;
} } }
package com.taotao.common.utils;

import java.util.List;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.taotao.common.pojo.TaotaoResult; /**
* 淘淘商城自定义响应结构
*/
public class JsonUtils { // 定义jackson对象
private static final ObjectMapper MAPPER = new ObjectMapper(); /**
* 将对象转换成json字符串。
* <p>Title: pojoToJson</p>
* <p>Description: </p>
* @param data
* @return
*/
public static String objectToJson(Object data) {
try {
String string = MAPPER.writeValueAsString(data);
return string;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
} /**
* 将json结果集转化为对象
*
* @param jsonData json数据
* @param clazz 对象中的object类型
* @return
*/
public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
try {
T t = MAPPER.readValue(jsonData, beanType);
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
} /**
* 将json数据转换成pojo对象list
* <p>Title: jsonToList</p>
* <p>Description: </p>
* @param jsonData
* @param beanType
* @return
*/
public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
List<T> list = MAPPER.readValue(jsonData, javaType);
return list;
} catch (Exception e) {
e.printStackTrace();
} return null;
} }

淘淘商城自定义响应结构

@Controller
public class IndexController {
@Autowired
private ContentService contentService; @RequestMapping("/index")
public String showIndex(Model model) {
String adJson = contentService.getContentlist();
model.addAttribute("ad1", adJson); return"index";
}
}

==============================================

参考资料:

淘淘商城-内容分类管理 修改、删除实现、内容列表展示

@RequestParam、@RequestBody和@ModelAttribute区别

end