GitHub地址:https://github.com/leebingbin/Framework.Blade

 

搭建基于SSM的分布式电子商城的框架开源方便大家二次开发

 

1.   聊聊电商行业

1.1.   电商行业发展

 

    近年来,中国的电子商务快速发展,交易额连创新高,电子商务在各领域的应用不断拓展和深化、相关服务业蓬勃发展、支撑体系不断健全完善、创新的动力和能力 不断增强。电子商务正在与实体经济深度融合,进入规模性发展阶段,对经济社会生活的影响不断增大,正成为我国经济发展的新引擎。

    中国电子商务研究中心数据显示,截止到2012年底,中国电子商务市场交易规模达7.85万亿人民币,同比增长30.83%。其中,B2B电子商务交易额 达6.25万亿,同比增长27%。而2011年全年,中国电子商务市场交易额达6万亿人民币,同比增长33%,占GDP比重上升到13%;2012年,电 子商务占GDP的比重已经高达15%。预计未来我国电子商务规模突破十万亿大关也不是个问题。

   

1.1.   11.11

224418_nZFW_3375733.png

 

1.2.   电商行业技术特点

Ø  技术新

Ø  技术范围广

Ø  分布式

Ø  高并发、集群、负载均衡、高可用

Ø  海量数据

Ø  业务复杂

Ø  系统安全

 

2.   电子商城

2.1.   电子商城简介

        电子网上商城是一个综合性的B2C平台,类似京东商城、天猫商城。会员可以在商城浏览商品、下订单,以及参加各种活动。

        管理员、运营可以在平台后台管理系统中管理商品、订单、会员等。

        客服可以在后台管理系统中处理用户的询问以及投诉。

2.2.   功能架构

2.2.1.    系统功能图

224630_VPSe_3375733.png

2.2.2.    功能描述

后台管理系统:管理商品、订单、类目、商品规格属性、用户管理以及内容发布等功能。

前台系统:用户可以在前台系统中进行注册、登录、浏览商品、首页、下单等操作。

会员系统:用户可以在该系统中查询已下的订单、收藏的商品、我的优惠券、团购等信息。

订单系统:提供下单、查询订单、修改订单状态、定时处理订单。

搜索系统:提供商品的搜索功能。

单点登录系统:为多个系统之间提供用户登录凭证以及查询登录用户的信息。

2.3.   技术架构

2.3.2.  传统架构

224937_eEAd_3375733.png

 

思考:有什么问题?

1、  模块之间耦合度太高,其中一个升级其他都得升级

2、  开发困难,各个团队开发最后都要整合一起

3、  系统的扩展性差

4、不能灵活的进行分布式部署。

2.3.2.    分布式系统架构

225137_XMGV_3375733.png

分布式架构:

把系统按照模块拆分成多个子系统。

优点:

1、把模块拆分,使用接口通信,降低模块之间的耦合度。

2、把项目拆分成若干个子项目,不同的团队负责不同的子项目。

3、增加功能时只需要再增加一个子项目,调用其他系统的接口就可以。

4、可以灵活的进行分布式部署。

缺点:

系统之间交互需要使用远程通信,接口开发增加工作量。

2.3.3.    技术选型(主要技术)

l  Spring、SpringMVC、Mybatis

l  JSP、JSTL、jQuery、jQuery plugin、EasyUI、KindEditor(富文本编辑器)、CSS+DIV

l  Redis(缓存服务器)

l  Solr(搜索)

l  httpclient(调用系统服务)

l  Mysql

|  Nginx(web服务器)

l   

2.4.   开发工具和环境

IntelliJ IDEA 2016.3 

Maven 3.3.9

Tomcat 8.0(Maven Tomcat Plugin)

JDK 1.8

Mysql 5.7

Nginx 1.8.0

Redis 3.0.0

Mac OS Yosemite操作系统

Git(版本管理)

 

3.   后台管理系统工程结构

3.1.   maven管理的好处

1、项目构建。Maven定义了软件开发的整套流程体系,并进行了封装,开发人员只需要指定项目的构建流程,无需针对每个流程编写自己的构建脚本。

2、依赖管理。除了项目构建,Maven最核心的功能是软件包的依赖管理,能够自动分析项目所需要的依赖软件包,并到Maven中心仓库去下载。

A)管理依赖的jar包

B)管理工程之间的依赖关系。

 

3.2.   Maven本地仓库

    关于Maven配置和使用详见我的博客:

    1、https://my.oschina.net/u/3375733/blog/1546556

    2、https://my.oschina.net/u/3375733/blog/1546559

3.3.   依赖管理

Maven管理的工程结构:

不使用maven:工程部署时需要手动复制jar包。完成工程构建。非常繁琐。

使用maven进行工程构建:

使用maven可以实现一步构建。

3.3.1.    后台管理系统的工程结构

092527_ZgNg_3375733.png

3.4.   创建数据库

1、安装mysql数据库

2、在mysql中创建一个blade数据库

3、导入数据库脚本。

3.4.1.   Mybatis逆向工程

    执行逆向工程:

    使用官方网站的mapper自动生成工具mybatis-generator-core-1.3.2来生成po类和mapper映射文件。

3.4.2.   整合思路

1、Dao层:

    mybatis整合spring,通过spring管理SqlSessionFactory、mapper代理对象。需要mybatis和spring的整合包。

2、Service层:

所有的实现类都放到spring容器中管理。由spring创建数据库连接池,并有spring管理事务。

3、表现层:

Springmvc整合spring框架,由springmvc管理controller。

3.5.  分页处理

3.5.1.   Mybatis分页插件 - PageHelper说明

    如果你也在用Mybatis,建议尝试该分页插件,这个一定是最方便使用的分页插件。

该插件目前支持Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六种数据库分页。

3.5.2.    使用方法

第一步:在Mybatis配置xml中配置拦截器插件:

<plugins>

    <!-- com.github.pagehelper为PageHelper类所在包名 -->

    <plugin interceptor="com.github.pagehelper.PageHelper">

        <!-- 设置数据库类型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六种数据库-->       

        <property name="dialect" value="mysql"/>

    </plugin>

</plugins>

第二步:在代码中使用

1、设置分页信息:

    //获取第1页,10条内容,默认查询总数count

    PageHelper.startPage(1, 10);



    //紧跟着的第一个select方法会被分页

List<Country> list = countryMapper.selectIf(1);

2、取分页信息

//分页后,实际返回的结果list类型是Page<E>,如果想取出分页信息,需要强制转换为Page<E>,

Page<Country> listCountry = (Page<Country>)list;

listCountry.getTotal();

3、取分页信息的第二种方法

//获取第1页,10条内容,默认查询总数count

PageHelper.startPage(1, 10);

List<Country> list = countryMapper.selectAll();

//用PageInfo对结果进行包装

PageInfo page = new PageInfo(list);

//测试PageInfo全部属性

//PageInfo包含了非常全面的分页属性

assertEquals(1, page.getPageNum());

assertEquals(10, page.getPageSize());

assertEquals(1, page.getStartRow());

assertEquals(10, page.getEndRow());

assertEquals(183, page.getTotal());

assertEquals(19, page.getPages());

assertEquals(1, page.getFirstPage());

assertEquals(8, page.getLastPage());

assertEquals(true, page.isFirstPage());

assertEquals(false, page.isLastPage());

assertEquals(false, page.isHasPreviousPage());

assertEquals(true, page.isHasNextPage());

 

3.5.3.   Mapper

使用逆向工程生成的mapper文件。

 

3.5.4.   Service

@Service

public class ItemServiceImpl implements ItemService {

 

     @Autowired

     private TbItemMapper itemMapper;

     @Override

     public EasyUIResult getItemList(Integer page, Integer rows) throws Exception {

           TbItemExample example = new TbItemExample();

           //设置分页

           PageHelper.startPage(page, rows);

           List<TbItem> list = itemMapper.selectByExample(example);

           //取分页信息

           PageInfo<TbItem> pageInfo = new PageInfo<>(list);

           long total = pageInfo.getTotal();

           EasyUIResult result = new EasyUIResult(total, list);

          

           return result;

     }

 

}

 

3.5.5.   Controller

@Controller

@RequestMapping("/item")

public class ItemController {

    

     @Autowired

     private ItemService itemService;

 

     @RequestMapping("/list")

     //设置相应的内容为json数据

     @ResponseBody

     public EasyUIResult getItemlist(@RequestParam(defaultValue="1")Integer page,

                @RequestParam(defaultValue="30")Integer rows) throws Exception {

           //查询商品列表

           EasyUIResult result = itemService.getItemList(page, rows);

          

           return result;

     }

}

 

3.6.   跨域问题

    使用json数据测试。如果ajax请求的是同一个工程中taotao-portal的json数据没有问题,可以直接显示出来。如果请求的是taotao-rest工程中json数据,会发生错误。

101157_W2y8_3375733.png

跨域问题:浏览器一个安全的限制,不允许js跨域请求资源,

101315_edyG_3375733.png

    如何解决跨域问题:使用jsonp来解决跨域问题。

    jsonp的原理:

    浏览器在js请求中,是允许通过script标签的src跨域请求,可以在请求的结果中添加回调方法名,在请求页面中定义方法,既可获取到跨域请求的数据。

101606_9O1v_3375733.png

3.6.1.   服务实现

1.    对应数据格式创建pojo类:

public class ItemCat {

     //转换成json数据时使用u作为key                                                                                                                      

     @JsonProperty("u")

     private String url;

    

     @JsonProperty("n")

     private String name;

    

     @JsonProperty("i")

     private List<?> item;

}

2.    返回值POJO:

 

public class ItemCatResult {                                                                                                                               

    

     private List<?> data;

 

     public List<?> getData() {

           return data;

     }

 

     public void setData(List<?> data) {

           this.data = data;

     }

    

}

 

3.    Service

@Service

public class ItemCatServiceImpl implements ItemCatService {

 

     @Autowired

     private TbItemCatMapper itemCatMapper;

    

     @Override

     public ItemCatResult queryAllCategory() throws Exception {

          

           ItemCatResult result = new ItemCatResult();

           result.setData(getItemCatList(0l));

          

           return result;

     }

    

     /**

      * 查询分类列表

      * <p>Title: getItemCatList</p>

      * <p>Description: </p>

      * @param parentid

      * @return

      */

     private List<?> getItemCatList(long parentid) {

           TbItemCatExample example = new TbItemCatExample();

           Criteria criteria = example.createCriteria();

           //查询parentid为0的分类信息

           criteria.andParentIdEqualTo(parentid);

           List<TbItemCat> list = itemCatMapper.selectByExample(example);

           List dataList = new ArrayList();

           for (TbItemCat tbItemCat : list) {

                //判断是否为父节点

                if (tbItemCat.getIsParent()) {

                     ItemCat itemCat = new ItemCat();

                     itemCat.setUrl("/category/" + tbItemCat.getId() + ".html");

                     itemCat.setName(tbItemCat.getName());

                     //递归调用

                     itemCat.setItem(getItemCatList(tbItemCat.getId()));

                     //添加到列表

                     dataList.add(itemCat);

                } else {

                     String catItem = "/item/" + tbItemCat.getId() + ".html|" + tbItemCat.getName();

                     dataList.add(catItem);

                }

           }

           return dataList;

     }

 

}

 

4.    Controller

    要返回json数据,还需要使用回调方法把json数据包装起来。所以需要controller添加回调支持,不能直接返回一个ItemCatResult对象。

1.        方法一:

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

@RequestMapping("/all")

     @ResponseBody

     public MappingJacksonValue queryAll(String callback) throws Exception {

           //查询分类列表

           ItemCatResult result = itemCatService.queryAllCategory();

           //包装jsonp

           MappingJacksonValue jacksonValue = new MappingJacksonValue(result);

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

           jacksonValue.setJsonpFunction(callback);

          

           return jacksonValue;

     }

 

 

 
 
 
 
 
 
 
 
 
 
2.        方法二

    先把ItemCatResult对象转换成json字符串,然后使用字符串拼接的方法拼装成jsonp格式的数据。需要设置相应结果的MediaType。

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

     @ResponseBody

     public String queryAll(String callback) throws Exception {

           //查询分类列表

           ItemCatResult result = itemCatService.queryAllCategory();

           //把对象转换成json数据

           String jsonResult = JsonUtils.objectToJson(result);

           //拼接字符串

           String resultStr = callback + "(" + jsonResult + ");";

          

           return resultStr;

     }

5.   页面实现

104431_eiOa_3375733.png

 

 

 

本文为博主原创文章,转载请注明出处!

https://my.oschina.net/u/3375733/blog/

 

转载于:https://my.oschina.net/u/3375733/blog/1546527

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐