# demo-service2-support
**Repository Path**: CSL2014/demo-service2-support
## Basic Information
- **Project Name**: demo-service2-support
- **Description**: No description available
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 13
- **Created**: 2022-05-15
- **Last Updated**: 2022-05-15
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Demo-service-xxx系列的使用说明
这是一套简单易用、支持DDD与微服务的技术框架,它一方面演示了整个微服务的技术架构,同时为微服务下如何打造支持快速交付的技术中台提出了全新的思想。
该示例包含如下项目:
```bash
demo-parent 本示例所有项目的父项目,它集成了springboot, springcloud,并定义各项目如何maven打包
demo-service-eureka 微服务注册中心eureka,特别是高可用eureka集群
demo-service-config 微服务配置中心config
demo-service-turbine 各微服务断路器运行状况监控器turbine
demo-service-zuul 服务网关zuul
demo-service-parent 各业务微服务(无数据库访问)的父项目
demo-service-support 各业务微服务(无数据库访问)底层技术框架
demo-service-customer 用户管理微服务(无数据库访问)
demo-service-product 产品管理微服务(无数据库访问)
demo-service-supplier 供应商管理微服务(无数据库访问)
demo-service2-parent 各业务微服务(有数据库访问)的父项目
demo-service2-support 各业务微服务(有数据库访问)底层技术框架
demo-service2-customer 用户管理微服务(有数据库访问)
demo-service2-product 产品管理微服务(有数据库访问)
demo-service2-supplier 供应商管理微服务(有数据库访问)
demo-service2-order 订单管理微服务(有数据库访问)
```
本框架简单易用、支持DDD与微服务,它有如下几个特点:
## 1. 易于业务变更与维护
我们现在处于快速变化的时代,一方面市场与业务在快速变更,另一方面技术架构在快速更迭。激烈的市场竞争要求技术团队需要更快的交付速度,但许多团队由于项目编码过于繁杂,变更越来越困难,维护成本越来越高,交付速度越来越慢。代码编写越简洁,日后维护的成本就越低,更新速度就越快。因此,本框架打造了一个使业务编写更加简单快捷的技术框架。
### 1)单Controller的设计
在本框架中,不需要为每个业务模块编写Controller,整个系统只有2个Controller(增删改操作一个,查询一个)。通过规范,首先让业务开发人员在开发代码时,将前端的Json与后台的值对象对应起来,那么本框架就通过反射,自动地将前端Json中的数据,转换成后台的值对象,然后通过反射去调用相应的Service。这样的设计,既避免了以往设计中写大量的Controller,使系统开发成本高而不易维护与变更,又是的业务开发人员没有机会将业务代码写到Controller中,而是规范地编写到Bus/Service中,从而规范了系统分层,有利于日后的维护。
在使用单Controller以后,前端所有功能的增删改操作,以及基于id的get/load操作,都是访问的OrmController。前端在访问OrmController时,输入如下http请求:
```bash
http://localhost:9003/orm/{bean}/{method}
```
例如:
```bash
GET请求:http://localhost:9003/orm/product/deleteProduct?id=P00006
```
或者
```bash
POST请求:http://localhost:9003/orm/product/saveProduct
"id=P00006&name=ThinkPad+T220&price=4600&unit=%E4%B8%AA&supplierId=S0002&classify=%E5%8A%9E%E5%85%AC%E7%94%A8%E5%93%81"
```
{bean}是配置在Spring中的bean.id,{method}是该bean中需要调用的方法(注意,此处不支持方法的重载,如果出现重载,它将去调用同名方法中的最后一个)。
如果要调用的方法有值对象,必须将值对象放在方法的第一个参数上。如果要调用的方法既有值对象,又有其它参数,则值对象中的属性与其它参数都这样调用:
要调用的方法:saveProduct(product, saveMode);
```bash
POST请求:http://localhost:9003/orm/product/saveProduct
"id=P00006&name=ThinkPad+T220&price=4600&unit=%E4%B8%AA&supplierId=S0002&classify=%E5%8A%9E%E5%85%AC%E7%94%A8%E5%93%81&saveMode=1"
```
注意:OrmController不包含任何权限校验,配置在Spring中的所有bean中的所有方法都可以被前端调用,因此通常需要在OrmController之前进行一个权限校验,来规范前端可以调用的方法。可以使用一个服务网关或filter进行校验。
### 2)单Dao的设计
在本框架中,不需要为每个业务模块编写Dao,所有的Service都只需要配一个Dao。那么如何进行持久化呢?将每个值对象对应的表,以及值对象中每个属性对应的字段,通过vObj.xml配置文件进行对应,那么通用的BasicDao就可以通过配置文件形成SQL,并最终完成数据库持久化操作。vObj.xml配置文件:
```bash
```
值对象中可以设计很多属性变量,但只有最终做持久化的属性变量才需要配置。这样可以使值对象的设计具有更大的空间去做更多的转换与操作(充血模型的设计)。
有了以上设计以后,每个Service都必须有一个dao的属性变量,并在Spring中统一注入BasicDao(如果要使用DDD的功能支持,注入Repository;如果要使用Redis缓存,注入RepositoryWithCache)。
有了以上设计,业务开发人员只需要在系统中编写前端界面、Service与值对象,就可以完成业务开发,而Service与值对象的设计都源于领域驱动设计。
### 3)数据查询的设计
本框架采用CQRS(命令与查询职责分离)的设计模式,所有的SQL查询都使用另一个Controller(QueryController)来进行查询(注意:基于id的get/load方法使用OrmController来查询)。
在进行查询时,前端输入http请求:
```bash
http://localhost:9003/query/{bean}
```
该请求既可以接收POST请求,也可以接收GET请求。{bean}是配置在Spring中的Service。QueryController通过该请求,在Spring中找到Service,并调用Service.query(map)进行查询,此处的map就是该请求传递的所有查询参数。
本框架在查询时采用了单Service的设计,既所有的查询都是配置QueryService进行查询,但注入的是不同的Dao,就可以完成各自不同的查询。每个Dao都是通过MyBatis框架,注入同一个Dao但配置不同的mapper,就可以完成不同的查询。因此,先配置MyBatis的Mapper文件诸如:
```bash
and id = #{id}
select count(*) from (
) count
limit #{size} offset #{firstRow}
limit #{pageSize} offset #{startNum}
```
然后将其注入到Spring中,完成相应的配置,就可以进行查询:
```bash
```
此外,如果希望在查询前与查询后加入某些处理程序,则继承QueryServiceImpl并重载beforeQuery或afterQuery,例如:
```bash
/**
* The implement of the query service for products.
* @author fangang
*/
public class ProductQueryServiceImpl extends QueryServiceImpl {
@Autowired
private SupplierService supplierService;
@Override
protected ResultSet afterQuery(Map params,
ResultSet resultSet) {
@SuppressWarnings("unchecked")
List list = (List)resultSet.getData();
List listOfIds = new ArrayList<>();
for(Product product : list) {
Long supplierId = product.getSupplierId();
listOfIds.add(supplierId);
//Supplier supplier = supplierService.loadSupplier(supplierId);
//product.setSupplier(supplier);
}
List listOfSuppliers = supplierService.loadSuppliers(listOfIds);
Map