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系统)
需要把内容进行分类,分类应该是一个树形结构。在展示首页时,可以根据分类取内容信息,把内容展示到页面。
在后台管理内容及内容分类的系统就叫做cms系统。
先实现内容的分类管理再实现内容管理。
3.1 内容分类管理
3.1.1 内容分类初始化
需求分析
初始化树形视图的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>
@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 内容管理
内容管理表:
3.2.2 内容添加
需求分析:
内容表单提交:
请求的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
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 首页大广告方案
优点:有利于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层
接收内容分类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; } }
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(); } } }
http://localhost:8081/rest/content/list/89
4.4 Httpclient的使用
4.4.1 什么是httpclient
HttpClient 是 Apache 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
下载地址:
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; } }
5 大广告位展示
5.1 需求分析
需要创建一个json字符串传递给jsp:
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