如何做一个电商系统(三)

1.搭建前台系统

1.1.前台系统架构

如何做一个电商系统(三)_第1张图片
image.png

在互联网系统开发当中,我们一般都是采用了分层的方式来架构系统,即:

(1)门户层(门户系统):网站的入口

i、渲染视图,提供用户访问的页面。

ii、不查询数据库,数据来自对远程服务(接口)的调用。

(2)服务层:基于restful,以接口的形式对外提供公共的服务。

i、连接数据库,返回json格式的数据。

1.1.1.分层架构的好处

(1)、有利于系统的维护和拓展。

(2)、有利于SOA服务治理的基础。

1.2.搭建服务层系统

1.2.1.系统简介

基于RESTful实现。以接口的形式,对外提供公共的服务。(比如购物车、导航菜单、搜索、订单等等)

RESTful是一种接口设计理念,即:

(1)不同的请求方式,对应不同的业务类型:

       GET   :查询

       POST  :添加

       PUT   :更新

       DELETE: 删除

(2)返回json格式数据。

1.2.2.技术选择

核心框架:Spring+SpringMVC+Mybatis-plus

数 据 库:MySQL

前端框架:无

1.2.3.配置步骤

思路:
(1)创建项目,导入jar依赖。

(2)整合SSM框架。

1.2.3.1.第一步:创建maven项目(war)模型

注意:(1)项目继承ego-project。

  (2)使用maven module创建项目
如何做一个电商系统(三)_第2张图片
image.png

1.2.3.2.第二步:导入jar依赖

导包说明:

(1)ego-base子工程

(2)Spring核心包

(3)SpringMVC相关包

(4)AOP相关包

(5)JDBC、事物相关包

(6)Mybatis-plus及整合包

(7)JSON依赖包

导入插件:Tomcat插件(开发阶段,启动项目,对外发布接口)

     

  4.0.0

  

    cn.gzsxt.ego

    ego-project

    1.0

  

  cn.gzsxt.ego

  ego-rest

  1.0

  war

  

    

       cn.gzsxt.ego

        ego-base

        1.0

    

    

    

    

       org.springframework

       spring-context

    

    

    

       org.springframework

       spring-jdbc

    

    

    

       org.springframework

       spring-aspects

    

    

    

       org.springframework

       spring-webmvc

    

    

    

       org.mybatis

       mybatis-spring

    

    

    

    

       mysql

       mysql-connector-java

    

    

    

       com.alibaba

       druid

    

    

    

       com.fasterxml.jackson.core

       jackson-databind

    

  

  

       

            

            

                 org.apache.tomcat.maven

                 tomcat7-maven-plugin

                 

                     8081

                     /

                     UTF-8

                 

            

         

    


1.2.3.3.第三步:创建web.xml文件

说明:可以从ego-manager工程中拷贝,修改即可。

     



    

      

           characterEncodingFilter

           org.springframework.web.filter.CharacterEncodingFilter

           

               encoding

               utf-8

           

      

  

       characterEncodingFilter

       /*

  

    

       dispatcherServlet

       org.springframework.web.servlet.DispatcherServlet

       

           contextConfigLocation

           classpath:spring-*.xml

       

       

       1

    

    

       dispatcherServlet

       

        /rest/*

    


1.2.3.4.第四步:整合SSM框架

整合中所需要的配置文件,均可从ego-manager工程中拷贝,修改局部的配置即可。

1.2.3.4.1.Step1:Spring整合SpringMVC

创建spring-mvc.xml文件,做如下配置:

     



    

    

    

    


1.2.3.4.2.Step2:mybatis-plus整合spring

在这里,我们一定要有一个概念:任何持久层框架和Spring的整合,都是为了使用Spring的事物代理。

(1)创建resource.properties文件,配置数据库连接信息如下:

#配置数据源     

db.driver=com.mysql.jdbc.Driver

db.url=jdbc:mysql://localhost:3306/ego

db.username=root

db.password=gzsxt

(2)创建spring-data.xml文件,配置框架整合。

     



    

    

    

       

       

       

       

       

       

    

    

    

       

       

       

       

       

       

           

               

              

              

              

                  

                  

                  

              

           

       

       

       

    

    

    

       

       

    

    

    

    

        

        

        

        

        

        

        

    

    

     

           

     

    

    


1.2.3.5.第五步:整合测试

在这里我们使用静态数据(category.json),来模拟导航菜单接口的实现。

(1)拷贝category.json文件到webapp目录下。

如何做一个电商系统(三)_第3张图片
image.png

(2)更新项目、安装到本地仓库(updata、maven clean、maven install)

(3)启动项目

如何做一个电商系统(三)_第4张图片
image.png

查看控制台,启动成功!!!

如何做一个电商系统(三)_第5张图片
image.png

(4)浏览器访问,地址:http://localhost:8081/category.json,整合成功!!!

如何做一个电商系统(三)_第6张图片
image.png

1.3.搭建门户系统

1.3.1.系统简介

简单来说就是网站的入口,提供用户浏览、下单的操作页面。

门户系统不直接调用数据库,而是通过服务系统提供的接口获取数据。电商、互联网行业开发都是面向服务开发。

1.3.2.技术选择

核心框架:Spring+SpringMVC

数 据 库:无

前端技术:jquery、ajax、css+div、easyui等

1.3.3.配置步骤

思路:
(1)创建项目

(2)框架整合

1.3.3.1.第一步:创建maven项目(war模型)

注意:
(1)继承ego-project工程
(2)使用maven module创建子系统

如何做一个电商系统(三)_第7张图片
image.png

1.3.3.2.第二步:导入jar依赖

在门户系统中,不直接查询数据库,所以不需要导入数据库相关的jar包。

在门户系统中,用户能够搜索、浏览商品,提交订单等,所以需要添加jsp视图相关依赖。

     

  4.0.0

  

    cn.gzsxt.ego

    ego-parent

    1.0

  

  cn.gzsxt.ego

  ego-portal

  1.0

  war

  

       

              cn.gzsxt.ego

              ego-base

              1.0

       

       

       

           jstl

           jstl

       

       

           javax.servlet

           servlet-api

           provided

       

       

           javax.servlet

           jsp-api

           provided

       

           

           

           org.springframework

           spring-context

       

       

       

           org.springframework

           spring-webmvc

       

       

       

           com.fasterxml.jackson.core

           jackson-databind

       

  

  

       

       

       

           org.apache.tomcat.maven

           tomcat7-maven-plugin

           

              8082

              /

              UTF-8

           

       

    

    


1.3.3.3.第三步:创建web.xml文件

可以从ego-rest工程拷贝,修改配置

     



    

       index.html

    

    

      

           characterEncodingFilter

           org.springframework.web.filter.CharacterEncodingFilter

           

               encoding

               utf-8

           

      

  

       characterEncodingFilter

       /*

  

    

       dispatcherServlet

       org.springframework.web.servlet.DispatcherServlet

       

           contextConfigLocation

           classpath:spring-*.xml

       

       

       1

    

    

       dispatcherServlet

       

       *.html

    


1.3.3.4.第四步:导入jsp页面、静态资源

说明:
(1)静态资源放在/webapp目录
(2)jsp放到/WEB-INF/JSP目录下

如何做一个电商系统(三)_第8张图片
image.png

1.3.3.5.第五步:Spring整合SpringMVC

从ego-rest工程拷贝,修改部分配置即可。

     



    

    

    

    

    

    

       

       

    


1.3.3.6.第六步:整合测试

需求:访问门户系统首页。

(1)创建PageController类

package cn.gzsxt.portal.controller;     

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

@Controller

public class PageController {

    @RequestMapping("/index")

    public String showIndex(){

       return "index";

    }

}

(2)更新项目、安装到本地仓库。(update、clean、install)

(3)启动项目

如何做一个电商系统(三)_第9张图片
image.png

(4)访问首页,地址:http://localhost:8082

如何做一个电商系统(三)_第10张图片
image.png

前台系统搭建成功!!!

2.首页导航菜单实现

说明:首页导航菜单,是通过异步加载实现的。

好处:只有当展开导航菜单时,才会发送请求,从而节约cpu资源。

2.1.实现流程

如何做一个电商系统(三)_第11张图片
image.png

需要解决的问题:

(1)在rest系统中发布接口,封装导航菜单成json格式数据。

(2)在portal系统中,远程请求接口(跨域请求)。

2.2.跨越请求

2.2.1.什么是跨域(两个不同系统之间的访问、调用)

(1)域名不同,即两个不同的应用。

如何做一个电商系统(三)_第12张图片
image.png

(2)域名相同,但是端口不同,即同一个应用中的不同子系统。

image.png

2.2.2.Ajax跨域请求的缺陷

在ego-rest系统使用静态数据,模拟Ajax的跨域问题。

2.2.2.1.第一步:在ego-rest中添加category.json文件。(已实现)

2.2.2.2.第二步:在ego-portal中发送ajax请求

(1)创建testJsonp.jsp页面

<%@ page language="java" contentType="text/html; charset=UTF-8"     

    pageEncoding="UTF-8"%>











Insert title here














(2)修改PageController,新增访问非首页的方法。

@RequestMapping("/{page}")     

public String showPage(@PathVariable("page")String page){

    return page;

}

2.2.2.3.第三步:测试Ajax跨越

(1)重启启动ego-portal系统,访问testJsonp.jsp

如何做一个电商系统(三)_第13张图片
image.png

(2)点击按钮,发送异步请求

如何做一个电商系统(三)_第14张图片
image.png

测试发现,Ajax跨越请求失败了。

2.2.3.解决方案:jsonp跨域

在前面的测试中,我们发现Ajax跨越请求时,json数据被浏览器禁用了。

原因:浏览器禁止远程加载Json数据。(浏览器安全机制)

如何解决呢?

答:使用Jsonp方式。

2.2.3.1.Jsonp原理

Jsonp实现的前提:

浏览器允许跨越加载同源数据。

即在JavaScript脚本中发送请求,就可以远程加载js格式数据。

请求原理:

(1)异步请求的时候,加上一个名为callback的回调函数

(2)在接口中,将返回的json格式数据,伪装成js脚本格式。

(3)得到js格式数据后,提取里面的json数据。

如何做一个电商系统(三)_第15张图片
image.png

2.2.3.2.测试Jsonp

(1)修改testJsonp.jsp,指定异步请求为jsonp方式。


(2)在ego-rest工程中,修改category.json文件,将返回数据包装成js脚本。

image.png

(3)再次发送ajax异步请求,使用jsonp方式

如何做一个电商系统(三)_第16张图片
image.png

结论:
(1)jsonp是ajax技术中的一种异步请求方式。
(2)jsonp能实现跨越请求。
(3)jsonp跨越时,需要指定一个回调函数,并使用该函数将返回的数据伪装成js脚本。
(4)获取返回的js脚本后,jsonp自动提取其中的json数据。

2.3.首页导航菜单实现

思路:

(1)在rest工程中,开发接口,返回js格式数据。(参考category.json)

(2)在portal工程中,修改jsonp请求路径。请求rest接口。

2.3.1.第一部分:在rest工程中开发导航菜单接口

2.3.1.1.第一步:定义导航菜单POJO

导航菜单结构分析。(使用JsonViewer工具查看category.json)

如何做一个电商系统(三)_第17张图片
image.png

结论:
(1)需要定义两个POJO:菜单POJO、父目录节点POJO

(2)导航菜单的数据,是一次加载出来的。

创建菜单Menu类。(ego-base中创建)

package cn.gzsxt.base.pojo;     

import java.util.List;

/**

* 自定义导航菜单

* @author ccnulyq

*

*/

public class Menu {

    private List data;  //目录节点

    public List getData() {

       return data;

    }

    public void setData(List data) {

       this.data = data;

    }

    public Menu() {

       super();

    }

}

创建父目录节点MenuNode类

package cn.gzsxt.base.pojo;     

import java.util.List;

/**

* 自定义目录节点结构

* @author ccnulyq

*

*/

public class MenuNode {

    private String u;    //目录的链接

    private String n;    //目录的名称

    private List i;   //当请目录的子目录

    public MenuNode() {

       super();

    }

// 补全get、set方法

}

(3)重新编译ego-base工程,安装到本地仓库。(maven clean、maven install)

2.3.1.2.第二步:创建ItemCatService接口及其实现类

package cn.gzsxt.rest.service.impl;     

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import cn.gzsxt.base.mapper.ItemCatMapper;

import cn.gzsxt.base.pojo.ItemCat;

import cn.gzsxt.base.vo.Menu;

import cn.gzsxt.base.vo.MenuNode;

import cn.gzsxt.rest.service.ItemCatService;

@Service

public class ItemCatServiceImpl implements ItemCatService{

    @Autowired

    private ItemCatMapper itemCatMapper;

    @Override

    public Menu initMenu() {

       Menu menu = new Menu();

       //从返回值Menu的形式上来看,就是把一级目录查询出来即可。因此定义一个查询方法,通过parent_id=0查询一级目录

       List nodes = getNodesByParantId(0L);

       menu.setData(nodes);

       return menu;

    }

    //根据父目录的id,查询子目录

    private List getNodesByParantId(long parentId) {

       Map params = new HashMap<>();

       params.put("parent_id", parentId);

       List selectByMap = itemCatMapper.selectByMap(params);

       List nodes = new ArrayList<>();

       MenuNode node = null;

       for (ItemCat itemCat : selectByMap) {

           if(1==itemCat.getIsParent()){

              node = new MenuNode();

              node.setU("/products/"+itemCat.getId()+".html");          //u : "/products/1.html"

              node.setN(""+itemCat.getName()+"");     //n : "图书、音像、电子书刊"

              node.setI(getNodesByParantId(itemCat.getId()));  

              nodes.add(node);

           }else{

              nodes.add("/products/"+itemCat.getId()+".html|"+itemCat.getName());          //[3] : "/products/6.html|多媒体图书"

           }

       }

       return nodes;

    }

}

2.3.1.3.第三步:创建ItemCatController类

说明:需要将返回值,包装成js脚本数据。

(1)方式一:手动封装

package cn.gzsxt.rest.controller;     

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.MediaType;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.ResponseBody;

import cn.gzsxt.base.utils.JsonUtils;

import cn.gzsxt.base.vo.Menu;

import cn.gzsxt.rest.service.ItemCatService;

@Controller

public class ItemCatController {

    @Autowired

    private ItemCatService catService;

    /*

     * jsonp方法下,返回值,要使用回调函数来伪装js脚本

     * @return

     */

    @RequestMapping(value="/item/all",produces=MediaType.APPLICATION_JSON_VALUE + ";charset=utf-8")

    @ResponseBody

    public String getMenu(String callback){

       Menu menu = catService.initMenu();

       String jsonMenu = JsonUtils.objectToJson(menu);

       String jsMenu = callback+"("+jsonMenu+")";

       return jsMenu;

    }

}

(2)方式二:使用MappingJacksonValue对象封装

//使用MappingJacksonValue对象包装返回结果,并设置jsonp的回调方法

    @RequestMapping("/item/all")

    @ResponseBody

    public MappingJacksonValue queryAll(String callback) {

       //查询分类列表

       Menu menu = catService.getMenu();

       //包装jsonp

       MappingJacksonValue jacksonValue = new      MappingJacksonValue(menu);

       //设置包装的回调方法名

       jacksonValue.setJsonpFunction(callback);

       return jacksonValue;

    }

2.3.1.4.第四步:测试接口

在浏览器访问。

地址:http://localhost:8081/rest/item/all?callback=category.getDataService

image.png

2.3.2.第二部分:在portal工程中调用导航菜单接口

2.3.2.1.第一步:指定请求方式为jsonp

(1)修改lib-v1.js文件,指定导航菜单接口地址。

image.png

(2)修改lib-v1.js文件,指定请求方式为jsonp。

如何做一个电商系统(三)_第18张图片
image.png

2.3.2.2.第二步:测试导航菜单

(1)重启portal工程

(2)访问首页,请求导航菜单

如何做一个电商系统(三)_第19张图片
image.png

导航菜单开发成功!!!

3.CMS系统

3.1.概念

CMS系统即为内容管理系统。(Content Management System)

所谓的内容,就是出现在网页中的图片、文字、链接等。CMS系统就是用来维护网页中的内容的,实现网页中的内容动态、可变。

比如广告位的投放,秒杀栏、排行榜实时更新等,都需要通过CMS系统来实现。

3.2.CMS系统实现

如何做一个电商系统(三)_第20张图片
image.png

3.2.1.思路

(1)、将网页中的内容分类

按照网页的特性分类,然后将每一类网页划分成一个一个独立的区域。

如何做一个电商系统(三)_第21张图片
image.png

(2)在每一个内容分类下管理、维护各自的内容列表。

如何做一个电商系统(三)_第22张图片
image.png

3.2.2.数据库表关系

CMS系统主要涉及两种表:

(1)内容分类表:tb_content_category(作用:定位)

(2)内容表:tb_content

表之间的对应关系为1-N

如何做一个电商系统(三)_第23张图片
image.png

3.2.3.内容分类实现

3.2.3.1.需求

在后台管理页面,点击内容分类管理菜单,初始化内容分类树结构。该树结构可以添加、修改、删除节点。

如何做一个电商系统(三)_第24张图片
image.png

3.2.3.2.思路

(1)初始化内容分类导航树。(这里使用easyui-tree)

(2)对异步树进行维护。(添加节点、删除节点、更新节点)

3.2.3.3.第一部分:初始化内容分类导航树

3.2.3.3.1.第一步:初始化easyui异步树插件

如何做一个电商系统(三)_第25张图片
image.png

3.2.3.3.2.第二步:确定代码结构


| 

Controller

 | 

表现层,负责交互、绑定参数、响应视图

 |
| 

Service

 | 

业务层,负责业务逻辑实现(封装树结构)

 |
| 

Mapper

 | 

持久层,逆向工程生成,不需要开发。

 |

3.2.3.3.3.第三步:确定请求响应格式


| 

请求路径

 | 

/content/category/list

 |
| 

请求方式

 | 

GET请求

 |
| 

请求参数

 | 

id=nodeId(首次加载生成一级目录时,默认id=0)

 |
| 

响应格式

 | 

List (id,text,state:open|closed)

 |
3.2.3.3.4.第四步:创建ContentCategory类

在公共工程ego-base中创建。

package cn.gzsxt.base.pojo;     

import java.util.Date;

import com.baomidou.mybatisplus.annotations.TableField;

import com.baomidou.mybatisplus.annotations.TableId;

import com.baomidou.mybatisplus.annotations.TableName;

import com.baomidou.mybatisplus.enums.IdType;

@TableName(value="tb_content_category")

public class ContentCategory {

    @TableId(value="id",type=IdType.AUTO)

    private Long id;

    @TableField(value="parent_id")

    private Long parentId;

    private String name;

    private int status;

    @TableField(value="sort_order")

    private int sortOrdert;

    @TableField(value="is_parent")

    private byte isParent;

    private Date created;

    private Date updated;

    public ContentCategory() {

       super();

    }

    // 补全get、set方法

}
3.2.3.3.5.第五步:创建ContentCategoryMapper接口

在公共工程ego-base中创建。

package cn.gzsxt.base.mapper;     

import com.baomidou.mybatisplus.mapper.BaseMapper;

import cn.gzsxt.base.pojo.ContentCategory;

public interface ContentCategoryMapper extends      BaseMapper{

}
3.2.3.3.6.第六步:创建ContentCategoryService接口及其实现类
package cn.gzsxt.manager.service.impl;     

import java.util.ArrayList;

import java.util.Date;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import cn.gzsxt.base.mapper.ContentCategoryMapper;

import cn.gzsxt.base.pojo.ContentCategory;

import cn.gzsxt.base.vo.EUTreeNode;

import cn.gzsxt.base.vo.EgoResult;

import cn.gzsxt.manager.service.ContentCategoryService;

@Service

public class ContentCategoryServiceImpl implements      ContentCategoryService{

    @Autowired

    private ContentCategoryMapper mapper;

    @Override

    public List selectByParentId(Long parentId) {

       //定义返回值

       List nodes = new ArrayList<>();

       //封装查询条件,执行查询

       Map columnMap = new HashMap<>();

       columnMap.put("parent_id", parentId);

       List selectByMap =      mapper.selectByMap(columnMap);

       EUTreeNode node = null;

       for (ContentCategory c : selectByMap) {

           node = new EUTreeNode();

           node.setId(c.getId());

           node.setText(c.getName());

           //三目运算符

           node.setState(1==c.getIsParent()?"closed":"open");   

           nodes.add(node);

       }

       return nodes;

    }

}
3.2.3.3.7.第七步:创建ContentCategoryController类
package cn.gzsxt.manager.controller;     

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.ResponseBody;

import cn.gzsxt.base.vo.EUTreeNode;

import cn.gzsxt.manager.service.ContentCategoryService;

@Controller

@RequestMapping("/content/category")

public class ContentCategoryController {

    @Autowired

    private ContentCategoryService service;

    @RequestMapping(value="/list",method=RequestMethod.GET)

    @ResponseBody

    public List      selectByParentId(@RequestParam(name="id",defaultValue="0")Long      parentId){

       return service.selectByParentId(parentId);

    }

}
3.2.3.3.8.第八步:测试

(1)重新编译ego-manager工程。(clean、install)

(2)重新启动ego-manager。

(3)访问内容分类管理

3.2.3.4.第二部分:添加内容分类节点

3.2.3.4.1.第一步:前端js实现
如何做一个电商系统(三)_第26张图片
image.png
3.2.3.4.2.第二步:确定代码结构

| 

Controller

 | 

视图层,接收参数,将新增加的节点响应出去

 |
| 

Service

 | 

业务层,新增节点、更新父节点

 |
| 

Mapper

 | 

持久层,逆向工程生成,不需要开发。

 |
3.2.3.4.3.第三步:确定请求响应格式

| 

请求路径

 | 

/content/category/create

 |
| 

请求方式

 | 

POST

 |
| 

请求参数

 | 

parentId:node.parentId,   name:node.text

 |
| 

响应格式

 | 

{status:200,data:node}  (EgoResult类型)

 |
3.2.3.4.4.第四步:修改ContentCategoryService及其实现类,新增save方法

注意:先在ContentCategoryService接口中定义save方法

@Transactional(rollbackFor=Exception.class)

    @Override

    public EgoResult save(Long parentId, String name) {

       ContentCategory temp = new ContentCategory();

       temp.setParentId(parentId);

       temp.setName(name);

       temp.setIsParent((byte) 0);

       temp.setSortOrdert(1);

       temp.setCreated(new Date());

       temp.setStatus(1);

       temp.setUpdated(temp.getCreated());

       //mybatis-plus保存对象的时候,已经实现了对象的id自动同步。前提:数据库id是自增。

       mapper.insert(temp);

       /*

        * 判断当前添加节点的父节点是否是目录节点。

        *

        * 如果不是,则要修改其状态为父目录结构

        */

       ContentCategory category = mapper.selectById(parentId);

       if(0==category.getIsParent()){

           category.setIsParent((byte) 1);

           mapper.updateById(category);

       }

       return EgoResult.ok(temp);

    }
3.2.3.4.5.第五步:修改ContentCategoryController类,定义新增内容分类接口
@RequestMapping(value="/create",method=RequestMethod.POST)

    @ResponseBody

    public EgoResult create(Long parentId,String name){   

       EgoResult result = catService.save(name, parentId);

       return result;

    }
3.2.3.4.6.第六步:测试

(1)重新编译ego-base工程。(clean、install)

(2)重新启动ego-manager。

(3)新增内容分类节点。

3.2.3.5.第三部分:更新内容分类

3.2.3.5.1.第一步:前端js实现
image.png
3.2.3.5.2.第二步:确定请求响应格式

| 

请求路径

 | 

/content/category/updata

 |
| 

请求方式

 | 

POST

 |
| 

请求参数

 | 

id:node.id,   name:node.text

 |
| 

响应格式

 | 

{status:200,data:node}  (EgoResult类型)

 |
3.2.3.5.3.第三步:修改ContentCategoryService及其接口,新增update方法。

注意:先在service接口中定义方法。

@Override

    public EgoResult updateNode(String name, Long id) {

       ContentCategory contentCat = new ContentCategory();

       contentCat.setName(name);

       contentCat.setId(id);

       contentCatMapper.updateById(contentCat);

       return EgoResult.ok();

    }
3.2.3.5.4.第四步:修改ContentController类,定义更新的接口
@RequestMapping(value="/update",method=RequestMethod.POST)

    @ResponseBody

    public EgoResult updateNode(Long id,String name){

       EgoResult result = catService.updateNode(name, id);

       return result;

    }
3.2.3.5.5.第五步:测试

(1)重新编译ego-manager工程。(clean、install)

(2)重新启动ego-manager。

(3)更新内容分类节点。

3.2.3.6.第四部分:删除内容分类

3.2.3.6.1.第一步:前端js实现
image.png
3.2.3.6.2.第二步:确定请求响应格式

| 

请求路径

 | 

/content/category/delete

 |
| 

请求方式

 | 

POST

 |
| 

请求参数

 | 

id:node.id,   parentId:node.parentId

 |
| 

响应格式

 | 

{status:200,data:node}  (EgoResult类型)

 |
3.2.3.6.3.第三步:修改ContentCategoryService及其实现类,新增delete方法
    @Transactional     

    @Override

    public EgoResult deleteNode(Long id, Long parentId) {

       // 第一步:判断parent_id是否有值

       if (parentId == null) {

           parentId =      contentCategoryMapper.selectById(id).getParentId();

       }

       // 第二步:判断该节点是否是它的父节点的最后一个节点。如果是。那么需要将它的父节点修改为叶节点

       EntityWrapper wrapper = new      EntityWrapper<>();

       wrapper.eq("parent_id", parentId);

       //过滤只查询有效的状态

       wrapper.eq("status", 1);

       List categories =      contentCategoryMapper.selectList(wrapper);

       if (categories.size() == 1) {

           ContentCategory parentCategory =      contentCategoryMapper.selectById(parentId);

           // 父节点修改为叶节点

           parentCategory.setIsParent((byte) 0);

           parentCategory.setUpdated(new Date());

           contentCategoryMapper.updateById(parentCategory);

       }

       // 第三步:修改当前节点的状态值,修改为删除状态

       ContentCategory category =      contentCategoryMapper.selectById(id);

       category.setStatus(2);

       category.setUpdated(new Date());

       contentCategoryMapper.updateById(category);

       return EgoResult.ok();

    }
3.2.3.6.4.第四步:修改ContentCategoryController类,定义delete接口
@RequestMapping(value="/delete",method=RequestMethod.POST)

    @ResponseBody

    public EgoResult deleteNode(Long id,Long parentId){

       EgoResult result = catService.deleteNode(id, parentId);

       return result;

    }

3.2.4.内容管理实现

3.2.4.1.需求

根据内容分类id,查询数据库表tb_content,获取内容列表。

内容分类树使用easyui-tree组件,内容列表使用easyui-datagrid组件。

如何做一个电商系统(三)_第27张图片
image.png

3.2.4.2.思路

(1)实现内容列表查询。

(2)在内容分类节点下,维护内容列表。

3.2.4.3.第一部分:内容列表实现

3.2.4.3.1.第一步:加载easyui-datagrid插件

(1)初始化分类导航树(后台java已实现,见2.2.1.3.2章节)

如何做一个电商系统(三)_第28张图片
image.png

(2)选中内容分类节点

如何做一个电商系统(三)_第29张图片
image.png

(3)查询该节点下的内容列表

如何做一个电商系统(三)_第30张图片
image.png
3.2.4.3.2.第二步:确定代码结构

| 

Controller

 | 

获取分类ID,分页信息,响应列表数据

 |
| 

Service

 | 

分页查询逻辑

 |
| 

Mapper

 | 

逆向工程生成,不需要开发

 |
3.2.4.3.3.第三步:确定请求响应结构

| 

请求路径

 | 

/content/query/list

 |
| 

请求方式

 | 

GET

 |
| 

请求参数

 | 

{categoryId:0  ,  page:1  ,  rows:20}

 |
| 

响应格式

 | 

{total:20,rows:dataList}  (参见ego-base中的EUDataGridRestult类)

 |
3.2.4.3.4.第四步:创建Content类

在ego-base工程中创建!

package cn.gzsxt.base.pojo;     

import java.util.Date;

import com.baomidou.mybatisplus.annotations.TableField;

import com.baomidou.mybatisplus.annotations.TableId;

import com.baomidou.mybatisplus.annotations.TableName;

import com.baomidou.mybatisplus.enums.IdType;

@TableName(value="tb_content")

public class Content {

    @TableId(value="id",type=IdType.AUTO)

    private Long id;

    @TableField(value="category_id")

    private long categoryId;

    private String title;

    @TableField(value="sub_title")

    private String subTitle;

    @TableField(value="title_desc")

    private String titleDesc;

    private String url;

    private String pic;

    private String pic2;

    private String content;

    private Date created;

    private Date updated;

    public Content() {

       super();

    }

    // 补全get、set方法

}
3.2.4.3.5.第五步:创建ContentMapper接口

在ego-base工程中创建!

package cn.gzsxt.base.mapper;     

import com.baomidou.mybatisplus.mapper.BaseMapper;

import cn.gzsxt.base.pojo.Content;

public interface ContentMapper extends BaseMapper{

}
3.2.4.3.6.第六步:创建ContentService接口及其实现类
package cn.gzsxt.manager.service.impl;     

import java.util.Arrays;

import java.util.Date;

import java.util.List;

import org.apache.ibatis.session.RowBounds;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.mapper.EntityWrapper;

import cn.gzsxt.base.mapper.ContentMapper;

import cn.gzsxt.base.pojo.Content;

import cn.gzsxt.base.vo.EUDataGridResult;

import cn.gzsxt.base.vo.EgoResult;

import cn.gzsxt.manager.service.ContentService;

@Service

public class ContentServiceImpl implements ContentService{

    @Autowired

    private ContentMapper mapper;

    @Override

    public EUDataGridResult listByCatIdAndPage(Long categoryId, int      page, int rows) {

       EUDataGridResult result = new EUDataGridResult();

       /*

        * offset 偏移量  即limit函数中的start

        * limit  容量

        */

       RowBounds rowBounds = new RowBounds((page-1)*rows, rows);

       EntityWrapper wrapper = new EntityWrapper<>();

       wrapper.eq("category_id", categoryId);

List selectPage = mapper.selectPage(rowBounds,      wrapper);

       Integer count = mapper.selectCount(wrapper);

       result.setTotal(count);

       result.setRows(selectPage);

       return result;

    }

}
3.2.4.3.7.第七步:创建ContentController类
package cn.gzsxt.manager.controller;     

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.ResponseBody;

import cn.gzsxt.base.pojo.Content;

import cn.gzsxt.base.vo.EUDataGridResult;

import cn.gzsxt.base.vo.EgoResult;

import cn.gzsxt.manager.service.ContentService;

@Controller

@RequestMapping("/content")

public class ContentController {

    @Autowired

    private ContentService service;

    @RequestMapping(value="/query/list")

    @ResponseBody

    public EUDataGridResult selectByCatIdAndPage(Long      categoryId,Integer page,Integer rows){

       EUDataGridResult result =      service.listByCatIdAndPage(categoryId, page, rows);

       return result;

    }

}
3.2.4.3.8.第八步:测试

(1)重新编译ego-manager工程。(clean、install)

(2)重新启动ego-manager。

(3)查看内容列表。成功!!!

如何做一个电商系统(三)_第31张图片
image.png

3.2.4.4.第二部分:新增内容

3.2.4.4.1.第一步:前端js实现
如何做一个电商系统(三)_第32张图片
image.png
3.2.4.4.2.第二步:确定代码结构

| 

Controller

 | 

接收表单数据,响应保存结果

 |
| 

Service

 | 

保存逻辑实现

 |
| 

Mapper

 | 

逆向工程生成

 |
3.2.4.4.3.第三步:确定请求响应格式

| 

请求路径

 | 

/content/save

 |
| 

请求方式

 | 

POST

 |
| 

请求参数

 | 

Content类

 |
| 

响应格式

 | 

{status:200}  (EgoResult类型)

 |
3.2.4.4.4.第四步:修改ContentService接口及其实现类,新增save方法
@Override

public EgoResult addContent(Content content) throws Exception {

     //把图片信息保存至数据库

     content.setCreated(new Date());

     content.setUpdated(new Date());

     //把内容信息添加到数据库

     mapper.insert(content);

     return EgoResult.ok();

}
3.2.4.4.5.第五步:修改ContentController类,定义save接口
@RequestMapping("/save")

@ResponseBody

public EgoResult addContent(Content content) throws Exception {

     EgoResult result = service.addContent(content);

     return result;

    }

3.2.4.5.第三部分:更新内容

3.2.4.5.1.第一步:前端js实现
如何做一个电商系统(三)_第33张图片
image.png
3.2.4.5.2.第二步:确定请求响应格式

| 

请求路径

 | 

/content/edit

 |
| 

请求方式

 | 

POST

 |
| 

请求参数

 | 

Content类 

 |
| 

响应格式

 | 

{status:200}  (EgoResult类型)

 |
3.2.4.5.3.第三步:修改ContentService接口及其实现类,新增update方法
@Override

    public EgoResult update(Content content) {

       mapper.updateById(content);

       return EgoResult.ok();

    }
3.2.4.5.4.第四步:修改ContentController类,新增update接口
@RequestMapping("/edit")

    @ResponseBody

    public EgoResult update(Content Content){

       EgoResult result = service.update(Content);

       return result;

    }

3.2.4.6.第四部分:删除内容

3.2.4.6.1.第一步:前端js实现
如何做一个电商系统(三)_第34张图片
image.png

获取所有要删除的内容的id,封装到数组中。

如何做一个电商系统(三)_第35张图片
image.png
3.2.4.6.2.第二步:确定请求响应格式

| 

请求路径

 | 

/content/delete

 |
| 

请求方式

 | 

POST

 |
| 

请求参数

 | 

Ids[]:{1,2,3}  数组类型

 |
| 

响应格式

 | 

{status:200}  (EgoResult类型)

 |
3.2.4.6.3.第三步:修改ContentService接口及其实现类,新增delete方法
@Override

    public EgoResult delete(Integer[] ids) {      

       List idss = Arrays.asList(ids);

        mapper.deleteBatchIds(idss);

       return EgoResult.ok();

    }
3.2.4.6.4.第四步:修改ContentController类,新增delete接口
@RequestMapping("/delete")

    @ResponseBody

    public EgoResult delete(Integer[] ids){

       EgoResult result = service.delete(ids);

       return result;

    }

4.首页大广告实现

4.1.需求

访问门户系统首页,在大广位区域展示大广告位对应的内容。

4.2.实现流程

(1)、在CMS系统中维护大广告位的内容。

(2)、在REST系统中查询大广告位的内容列表,以接口的形式对外提供服务。

(3)、在portal门户系统中远程访问REST系统。

如何做一个电商系统(三)_第36张图片
image.png
11.第一部分:REST系统接口实现

需求:

根据内容分类id,查询tb_content表,获得大广告位内容列表。

4.3.1.第一步:确定代码结构


| 

Controller

 | 

定义接口规则(请求路径、请求方式、参数、响应值类型)

 |
| 

Service

 | 

定义查询逻辑

 |
| 

Mapper

 | 

查询数据库

 |

4.3.2.第二步:定义接口规则


| 

请求路径

 | 

/rest/content/category/{cid}

 |
| 

请求方式

 | 

GET

 |
| 

请求参数

 | 

/{cid}  路径变量

 |
| 

响应类型

 | 

EgoResult

 |
| 

示例

 | 

demo

 |

4.3.3.第三步:创建ContentService接口及其实现类

package cn.gzsxt.rest.service.impl;     

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import cn.gzsxt.base.mapper.ContentMapper;

import cn.gzsxt.base.pojo.Content;

import cn.gzsxt.base.utils.JsonUtils;

import cn.gzsxt.rest.service.ContentService;

@Service

public class ContentServiceImpl implements ContentService{

    @Autowired

    private ContentMapper mapper;

    @Override

    public EgoResult getContentByCatId(Long catId) {

Map columnMap = new HashMap<>();

       columnMap.put("category_id", catId);

       List list = mapper.selectByMap(columnMap);

       return EgoResult.ok(list);

    }

}

4.3.4.第四步:创建ContentController类

@RestController     

@RequestMapping("/content")

public class ContentController {

    @Autowired

    private ContentService contentService;

    @RequestMapping("/category/{cid}")

    public EgoResult getContentList(@PathVariable Long cid) {

       EgoResult result = contentService.getContentByCatId(cid);

       return result;

    }

}

4.4.第二部分:远程接口调用方式HttpClient

问题:现在我们已经开发好了接口了,那该如何调用这个接口呢?

答:使用Httpclient客户端。

4.4.1.Httpclient简介

4.4.1.1.什么是httpclient

HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。实现了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)

下载地址:http://hc.apache.org/

4.4.1.2.httpclient作用

在java代码中,发送Http请求。通常用来实现远程接口调用。

4.4.2.HttpClient测试

说明:在ego-base中测试

在ego-base工程中添加httpclient的pom依赖。

     

       org.apache.httpcomponents

       httpclient


4.4.2.1.执行GET请求

public static void doGet(){     

        // 创建Httpclient对象

        CloseableHttpClient httpclient = HttpClients.createDefault();

        // 创建http GET请求

        HttpGet httpGet = new HttpGet("http://www.oschina.net/");

        CloseableHttpResponse response = null;

        try {

            // 执行请求

            response = httpclient.execute(httpGet);

            System.out.println(response.getStatusLine());

            // 判断返回状态是否为200

            if (response.getStatusLine().getStatusCode() == 200) {

                String content =      EntityUtils.toString(response.getEntity(), "UTF-8");

                System.out.println("内容长度:" + content.length());

            }

        }catch(Exception e){

           e.printStackTrace();

        } finally {

            if (response != null) {

                try {

                  response.close();

              } catch (IOException e) {

                  e.printStackTrace();

              }

            }

            try {

              httpclient.close();

           } catch (IOException e) {

              e.printStackTrace();

           }

        }

4.4.2.2.执行GET带参数

public static void doGetParam(){     

        // 创建Httpclient对象

       CloseableHttpClient httpclient = HttpClients.createDefault();

       CloseableHttpResponse response = null;

       try {

        // 定义请求的参数

        URI uri = new      URIBuilder("http://www.baidu.com/s").setParameter("wd", "数据库").build();

        System.out.println(uri);

        // 创建http GET请求

        HttpGet httpGet = new HttpGet(uri);

            // 执行请求

            response = httpclient.execute(httpGet);

            // 判断返回状态是否为200

            if (response.getStatusLine().getStatusCode() == 200) {

                String content =      EntityUtils.toString(response.getEntity(), "UTF-8");

                System.out.println(content);

            }

        }catch(Exception e){

           e.printStackTrace();

        }finally {

            if (response != null) {

                try {

                  response.close();

              } catch (IOException e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

              }

            }

            try {

              httpclient.close();

           } catch (IOException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

           }

        }

    }

4.4.2.3.执行post请求

public static void doPost(){     

        // 创建Httpclient对象

        CloseableHttpClient httpclient =      HttpClientBuilder.create().setRedirectStrategy(new      LaxRedirectStrategy()).build();

        // 创建http POST请求

        HttpPost httpPost = new HttpPost("http://www.oschina.net/");

        CloseableHttpResponse response = null;

        try {

            // 执行请求

            response = httpclient.execute(httpPost);

            System.out.println(response.getStatusLine());

            // 判断返回状态是否为200

            if (response.getStatusLine().getStatusCode() == 200) {

                String content =      EntityUtils.toString(response.getEntity(), "UTF-8");

                System.out.println(content);

            }

        }catch(Exception e){

           e.printStackTrace();

        }finally {

            if (response != null) {

                try {

                  response.close();

              } catch (IOException e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

              }

            }

            try {

              httpclient.close();

           } catch (IOException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

           }

        }

    }

4.4.2.4.执行post带参数

public static void doPostParam() throws Exception{     

        // 创建Httpclient对象

        CloseableHttpClient httpclient =      HttpClientBuilder.create().setRedirectStrategy(new      LaxRedirectStrategy()).build();

        // 创建http POST请求

        HttpPost httpPost = new      HttpPost("http://www.oschina.net/search");

        // 设置2个post参数,一个是scope、一个是q

        List parameters = new      ArrayList();

        parameters.add(new BasicNameValuePair("scope", "project"));

        parameters.add(new BasicNameValuePair("q", "java"));

        // 构造一个form表单式的实体

        UrlEncodedFormEntity formEntity = new      UrlEncodedFormEntity(parameters);

        // 将请求实体设置到httpPost对象中

        httpPost.setEntity(formEntity);

        CloseableHttpResponse response = null;

        try {

            // 执行请求

            response = httpclient.execute(httpPost);

            System.out.println(response.getStatusLine());

            // 判断返回状态是否为200

            if (response.getStatusLine().getStatusCode() == 200) {

                String content =      EntityUtils.toString(response.getEntity(), "UTF-8");

                System.out.println(content);

            }

        } finally {

            if (response != null) {

                response.close();

            }

            httpclient.close();

        }

}

你可能感兴趣的:(如何做一个电商系统(三))