一个电商项目的Web服务化改造
项目,早期是随便瞎做的,没啥架构,连基本的设计也没。
有需求,实现需求,再反复修改。
大致就是这么做的。
最近,项目要重新架构,和某boss协商的结果是,采用阿里开源的dubbo实现服务化。
前几天,写了一篇dubbo入门案例,分布式服务框架Dubbo入门案例和项目源码
最近,开始实现基本业务功能模块的开发。完成1个模块,原有项目就接入进来,从而完成项目的服务化改造。
在和某boss的商讨之后,我们的做法是
1.只做单表操作,mysql数据库层次不写“关联查询”。
2.针对单个表,实现CRUD等基本操作。
3.层次划分
  mapper:基本的数据库CRUD,全部是原子操作
  dao:对mapper的数据进行组装,比如关联查询。
   之前,是在service层进行代码组装的。
  bizService:业务逻辑操作
  webService:对外服务层
  由于当前阶段,我们的业务逻辑比较简单,bizService和webService可以看成是1层的。
  
  好处:严格的层次划分,上层可以调用下层,同层之间不能互相调用。比如service不能调用其它的service。
4.结合Freemarker,写代码自动生成的工具。根据数据库表,自动生成标准化的代码。
  书写中...
  
  类结构
  Base*:基础的公共的类
  Brand: 具体的,以品牌brand表为例
  
  brand表结构
 
 CREATE TABLE `brand` (
`id` varchar(50) NOT NULL COMMENT 'ID',
`name` varchar(30) DEFAULT NULL COMMENT '品牌名称',
`logo` varchar(100) DEFAULT NULL COMMENT '品牌LOGO',
`isDelete` int(11) NOT NULL DEFAULT '0' COMMENT '是否删除',
`createTime` datetime DEFAULT NULL COMMENT '创建日期',
`updateTime` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='品牌表';

 Brand.java:数据库表对应的模型
 
/**
* 品牌
*
*/
public class Brand {
private String id;
private String name;
private String logo;
private Date createTime;
private Date updateTime;
private Integer isDelete; }

 
  BaseMapper.java:定义最通用的sql映射。注意,这个mapper没有对应的Mybatis xml配置。
 
import java.util.List;

public interface BaseMapper<ID, Entity> {
Entity get(ID id); List<Entity> listByIdList(List<String> idList); List<Entity> listAll(); int add(Entity entity); int update(Entity entity); int remove(ID id); int removeByIdList(List<ID> idList); }

  
  BrandMapper.java:品牌的sql映射,Java接口定义
  import java.util.List;
@Mapper
public interface BrandMapper extends BaseMapper<String, Brand> {
// read List<Brand> listByShopIdList(List<String> shopIdList); List<Brand> list(BrandBean brandBean); // write }

  BrandMapper.xml:品牌的sql映射,sql语句
 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.webservice.mapper.BrandMapper">
<sql id="columns">
id,name,logo,createTime,updateTime,isDelete
</sql> <select id="get" resultType="Brand">
select
<include refid="columns" />
from brand
where id =
#{id}
</select> <select id="list" resultType="Brand">
select
<include refid="columns" />
from brand where
isDelete=0
<if test="name != null and name !=''">
and name like '%${name}%'
</if>
order by createTime desc
</select> ...
}

  BaseDao.java:定义最基础、最通用的dao层接口。
 
 import java.util.List;

public interface BaseDao<ID, Entity,Bean> {
//read
Entity get(ID id); List<Entity> listByIdList(List<String> idList); List<Entity> list(Bean bean); List<Entity> listAll(); //write
int add(Entity entity); int update(Entity entity); int remove(ID id); int removeByIdList(List<ID> idList); }

  BrandDao.java: 品牌的dao接口
 
import java.util.List;

public interface BrandDao extends BaseDao<String, Brand,BrandBean> {
// read
List<Brand> listByShopIdList(List<String> shopIdList); List<String> listLogoByIdList(List<String> idList); // write }

  BrandDaoImpl.java:品牌的dao接口实现类
 
@Component
public class BrandDaoImpl implements BrandDao { @Autowired
private BrandMapper brandMapper; private Logger logger = Logger.getLogger(getClass()); @Override
public Brand get(String id) {
if(StringUtils.isEmpty(id)){
logger.error("The id is null");
return null;
}
return brandMapper.get(id);
} @Override
public List<Brand> listByIdList(List<String> idList) {
if (CollectionUtils.isEmpty(idList)) {
logger.error("The idList is empty");
return null;
}
return brandMapper.listByIdList(idList);
} }

  BrandService.java: 品牌,业务层的接口定义
  代码类似
  
  BrandServiceImpl.java:品牌,业务层的接口实现
  代码类似
  
  junit单元测试:测dao和service层,mapper层忽视
  BaseDaoTest.java:dao基础配置
 
//单元测试的mysql数据库,最好是单独的一套库,没有任何数据。如果开发和单元测试共用数据库,listAll之类的方法会有影响。
//单元测试:1.构造数据,2.执行操作,3.断言,4.回滚
//设置自动回滚
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
@ContextConfiguration(locations={"classpath*:spring-dataSource.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class BaseDaoTest {
public static final String NOT_EXIST_ID_STRING="not_exist_id_string";
public static final String NOT_EXIST_ID_INT="not_exist_id_int";
public static final String EXIST_NAME = "test";
public static final String NOT_EXIST_NAME = "not_exist_name";
} BrandDaoTest.java:brand的基础测试用例
public class BrandDaoTest extends BaseDaoTest { @Autowired
private BrandDao brandDao; // //////////////////////read//////////////////////////
@Test
public void testGet() {
Brand brand = TestDataCenter.brand();
brandDao.add(brand);
Brand dbBrand = brandDao.get(brand.getId());
assertNotNull(dbBrand);
} @Test
public void testGetNotExist() {
Brand brand = TestDataCenter.brand();
brandDao.add(brand);
Brand nullBrand = brandDao.get(NOT_EXIST_ID_STRING);
assertNull(nullBrand);
}

  BaseServiceTest.java:service基础配置
    代码类似
  BrandServiceTest.java:brand的基础测试用例
    代码类似
   
 单元测试结果图
  spring数据源配置,spring-dataSource.xml
 和普通项目一样
  
  除了Base基础接口,具体的业务类,计划通过代码生成工具自动生成。
  
  
  我们保证内部代码mapper层和dao层代码正确,保证service层正确,然后用dubbo把service的代码,稍微做点配置,对外提供服务。
  其它项目,比如front前端商城系统、mobile移动App、backend后端运营系统,直接调用咱们的服务接口即可。

一个电商项目的Web服务化改造的更多相关文章

  1. 一个电商项目的Web服务化改造6:单元测试4步走,构造数据、执行操作、断言、回滚

      最近一直在做一个电商项目,需要把原有单系统架构的项目,改造成基于服务的架构,SOA.     有点挑战,做完了,会有很大进步. 单元测试,在很早之前的文章已经介绍过.     可以在这里看到相关的 ...

  2. 一个电商项目的Web服务化改造3:改进方案の规范和约定、单表、单一职责

         最近一直在做一个电商项目,需要把原有单系统架构的项目,改造成基于服务的架构,SOA.      有点挑战,做完了,会有很大进步. 上一篇,我们描述了原有项目中的问题.  或者说是,本篇的基本 ...

  3. 一个电商项目的Web服务化改造5:面向服务的分层架构设计(有图有真相)

    最近一直在做一个电商项目,需要把原有单系统架构的项目,改造成基于服务的架构,SOA.     有点挑战,做完了,会有很大进步. 本篇,以我亲自画的3个图,阐述一下架构设计.   一.分层架构-总体图 ...

  4. 一个电商项目的Web服务化改造4:方案和架构,通用接口的定义和实现

        最近一直在做一个电商项目,需要把原有单系统架构的项目,改造成基于服务的架构,SOA.     有点挑战,做完了,会有很大进步. 上一篇,我们明确了我们的"规范和约定". 从 ...

  5. 一个电商项目的Web服务化改造2:现有项目的5个问题

         最近一直在做一个电商项目,需要把原有单系统架构的项目,改造成基于服务的架构,SOA.      有点挑战,做完了,会有很大进步, 1.现有项目的问题   1.1代码风格不统一     不同的 ...

  6. 一个电商项目的Web服务化改造7:Dubbo服务的调用,4个项目

    使用dubbo服务的过程,很简单,和之前学习的WebService完全一样,和本地接口调用也基本一致. dubbo和WebService的区别:我认为dubbo就是封装了WebService,然后提供 ...

  7. 如何一步一步用DDD设计一个电商网站(六)—— 给购物车加点料,集成售价上下文

    阅读目录 前言 如何在一个项目中实现多个上下文的业务 售价上下文与购买上下文的集成 结语 一.前言 前几篇已经实现了一个最简单的购买过程,这次开始往这个过程中增加一些东西.比如促销.会员价等,在我们的 ...

  8. 如何一步一步用DDD设计一个电商网站(十)—— 一个完整的购物车

     阅读目录 前言 回顾 梳理 实现 结语 一.前言 之前的文章中已经涉及到了购买商品加入购物车,购物车内购物项的金额计算等功能.本篇准备把剩下的购物车的基本概念一次处理完. 二.回顾 在动手之前我对之 ...

  9. 如何一步一步用DDD设计一个电商网站(七)—— 实现售价上下文

    阅读目录 前言 明确业务细节 建模 实现 结语 一.前言 上一篇我们已经确立的购买上下文和销售上下文的交互方式,传送门在此:http://www.cnblogs.com/Zachary-Fan/p/D ...

随机推荐

  1. IE浏览器 多版本之间切换

    由于Win7系统最低支持IE8的版本,不能通过安装IE7版本来达到要求. 有一个替代方案,通过IE自带Emulation来实现,实现步骤如下: 打开现有的IE浏览器 按下F12键 切换到“Emulat ...

  2. system.web section group下的section

    private Configuration _configuration; private ConfigurationSectionGroupCollection sectionGroups; pri ...

  3. MFC基础学习

    RECT rect = { }; //获取窗口的内部客户区矩形 GetClientRect(&rect); 模态和费模态对话框! 模态对话框只需要包含对话框头文件,定义对话框类,调用DoMod ...

  4. pandas删除满足特定列信息的行记录

    #!/usr/bin/python import pandas as pd df = pd.read_excel('c:\data\zichan.xlsx') df_sn = pd.read_exce ...

  5. dB/oct 解释

    分频斜率(也称滤波器的衰减斜率)用来反映分频点以下频响曲线的下降斜率,用分贝/倍频程(dB/oct)来表示.它有一阶(6 dB/oct).二阶(12 dB/oct).三阶(18 dB/oct)和四阶( ...

  6. 特征变化--->索引到标签的转换(IndexToString)

    package Spark_MLlib import org.apache.spark.ml.feature.{IndexToString, StringIndexer} import org.apa ...

  7. struts2标签---备忘录

    <s:form action="sloginAction" method="post"> <s:textfield label="用 ...

  8. Android_撕衣服小案例

    一直都觉得做安卓开发挺有意思,最近一段时间都在学习这方面的知识以及练习敲代码这次要说的是一个简单有趣的案例,相信大家也是看了标题才进来的吧,是不是有点迫不及待的想看看效果图,嘿嘿,算了还是直接给上源码 ...

  9. JavaWeb项目中引入spring框架

    主要步骤有以下3步: 1:下载spring的jar包2:在项目中web.xml中添加spring配置3:bean配置文件-applicationContext.xml 1:引入包,这个就不说了,官网下 ...

  10. js indexOf 列表筛选

    先来一堆效果图:  代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...