第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系统)


 

 

 

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

在后台管理内容及内容分类的系统就叫做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;
    }

}
View Code

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;
    }
}
View Code

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);
        
    }
View Code

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

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

 

 

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:

 

 

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 

posted @ 2019-10-14 19:36  Marlon康  阅读(343)  评论(0编辑  收藏  举报