一個電商專案的Web服務化改造

小雷FansUnion發表於2016-04-25
一個電商專案的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後端運營系統,直接呼叫我們們的服務介面即可。

相關文章