Appearance
SpringMVC
说明
说明
这里强调一下Controller的用法, 我提供的控制器有接口、也有抽象类, 将常用的CRUD接口全部封装到了接口中, 而抽象类则对具体的接口控制器进行了组合(实现了多个接口).
接口
- BaseController : 最基础的控制器, 只有一个常用的返回方法
- DeleteController : 封装了删除方法,并预留了 handlerDelete 接口,供子类重写。
- PageController : 封装了分页查询方法,并暴露了一些方法供子类扩展。
代码
java
/**
* 分页控制器
*
* @param <Entity> 实体
* @param <PageQuery> 分页参数
*/
public interface PageController<Id extends Serializable, Entity extends SuperEntity<Id>, SaveVO, UpdateVO, PageQuery, ResultVO>
extends BaseController<Id, Entity, SaveVO, UpdateVO, PageQuery, ResultVO> {
/**
* 处理查询参数
*
* @param params 前端传递的参数
* @author acuity
* @date 2021/7/3 3:25 下午
* @create [2021/7/3 3:25 下午 ] [acuity] [初始创建]
*/
default void handlerQueryParams(PageParams<PageQuery> params) {
}
/**
* 执行分页查询
* <p>
* 子类可以覆盖后重写查询逻辑
*
* @param params 分页参数
* @return 分页信息
*/
default IPage<Entity> query(PageParams<PageQuery> params) {
// 处理查询参数,如:覆盖前端传递的 current、size、sort 等参数 以及 model 中的参数 【提供给子类重写】【无默认实现】
handlerQueryParams(params);
// 构建分页参数(current、size)和排序字段等
IPage<Entity> page = params.buildPage(getEntityClass());
Entity model = BeanUtil.toBean(params.getModel(), getEntityClass());
// 根据前端传递的参数,构建查询条件【提供给子类重写】【有默认实现】
QueryWrap<Entity> wrapper = handlerWrapper(model, params);
// 执行单表分页查询
getSuperService().page(page, wrapper);
return page;
}
/**
* 处理对象中的非空参数和扩展字段中的区间参数,可以覆盖后处理组装查询条件
*
* @param model 实体类
* @param params 分页参数
* @return 查询构造器
*/
default QueryWrap<Entity> handlerWrapper(Entity model, PageParams<PageQuery> params) {
return Wraps.q(model, params.getExtra(), getEntityClass());
}
/**
* 获取echo Service
*
* @return
*/
default EchoService getEchoService() {
return null;
}
/**
* 处理查询后的数据
* <p>
* 如:执行@Echo回显
*
* @param page 分页对象
*/
default void handlerResult(IPage<ResultVO> page) {
EchoService echoService = getEchoService();
if (echoService != null) {
echoService.action(page);
}
}
/**
* 分页查询
*
* @param params 分页参数
* @return 分页数据s
*/
@ApiOperation(value = "分页列表查询")
@PostMapping(value = "/page")
@WebLog(value = "'分页列表查询:第' + #params?.current + '页, 显示' + #params?.size + '行'", response = false)
default R<IPage<ResultVO>> page(@RequestBody @Validated PageParams<PageQuery> params) {
IPage<Entity> page = query(params);
IPage<ResultVO> voPage = BeanPlusUtil.toBeanPage(page, getResultVOClass());
// 处理查询后的分页结果, 如:调用EchoService回显字典、关联表数据等 【提供给子类重写】【有默认实现】
handlerResult(voPage);
return success(voPage);
}
}
/**
* 分页控制器
*
* @param <Entity> 实体
* @param <PageQuery> 分页参数
*/
public interface PageController<Id extends Serializable, Entity extends SuperEntity<Id>, SaveVO, UpdateVO, PageQuery, ResultVO>
extends BaseController<Id, Entity, SaveVO, UpdateVO, PageQuery, ResultVO> {
/**
* 处理查询参数
*
* @param params 前端传递的参数
* @author acuity
* @date 2021/7/3 3:25 下午
* @create [2021/7/3 3:25 下午 ] [acuity] [初始创建]
*/
default void handlerQueryParams(PageParams<PageQuery> params) {
}
/**
* 执行分页查询
* <p>
* 子类可以覆盖后重写查询逻辑
*
* @param params 分页参数
* @return 分页信息
*/
default IPage<Entity> query(PageParams<PageQuery> params) {
// 处理查询参数,如:覆盖前端传递的 current、size、sort 等参数 以及 model 中的参数 【提供给子类重写】【无默认实现】
handlerQueryParams(params);
// 构建分页参数(current、size)和排序字段等
IPage<Entity> page = params.buildPage(getEntityClass());
Entity model = BeanUtil.toBean(params.getModel(), getEntityClass());
// 根据前端传递的参数,构建查询条件【提供给子类重写】【有默认实现】
QueryWrap<Entity> wrapper = handlerWrapper(model, params);
// 执行单表分页查询
getSuperService().page(page, wrapper);
return page;
}
/**
* 处理对象中的非空参数和扩展字段中的区间参数,可以覆盖后处理组装查询条件
*
* @param model 实体类
* @param params 分页参数
* @return 查询构造器
*/
default QueryWrap<Entity> handlerWrapper(Entity model, PageParams<PageQuery> params) {
return Wraps.q(model, params.getExtra(), getEntityClass());
}
/**
* 获取echo Service
*
* @return
*/
default EchoService getEchoService() {
return null;
}
/**
* 处理查询后的数据
* <p>
* 如:执行@Echo回显
*
* @param page 分页对象
*/
default void handlerResult(IPage<ResultVO> page) {
EchoService echoService = getEchoService();
if (echoService != null) {
echoService.action(page);
}
}
/**
* 分页查询
*
* @param params 分页参数
* @return 分页数据s
*/
@ApiOperation(value = "分页列表查询")
@PostMapping(value = "/page")
@WebLog(value = "'分页列表查询:第' + #params?.current + '页, 显示' + #params?.size + '行'", response = false)
default R<IPage<ResultVO>> page(@RequestBody @Validated PageParams<PageQuery> params) {
IPage<Entity> page = query(params);
IPage<ResultVO> voPage = BeanPlusUtil.toBeanPage(page, getResultVOClass());
// 处理查询后的分页结果, 如:调用EchoService回显字典、关联表数据等 【提供给子类重写】【有默认实现】
handlerResult(voPage);
return success(voPage);
}
}
- PoiController : 封装了单体查询、详情查询、列表查询等方法。单体查询和详情查询的区别在于后者执行了@Echo回显。
- QueryController : 封装了单体查询、详情查询、列表查询等方法。单体查询和详情查询的区别在于后者执行了@Echo回显。
代码
java
/**
* 查询Controller
*
* @param <Entity> 实体
* @param <Id> 主键
* @param <PageQuery> 分页参数
* @param <ResultVO> 实体返回VO
*/
public interface QueryController<Id extends Serializable, Entity extends SuperEntity<Id>, SaveVO, UpdateVO, PageQuery, ResultVO>
extends PageController<Id, Entity, SaveVO, UpdateVO, PageQuery, ResultVO> {
/**
* 单体查询
*
* @param id 主键id
* @return 查询结果
*/
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "主键", dataType = "long", paramType = "path"),
})
@ApiOperation(value = "单体查询", notes = "单体查询")
@GetMapping("/{id}")
@WebLog("'查询:' + #id")
default R<ResultVO> get(@PathVariable Id id) {
Entity entity = getSuperService().getById(id);
return success(BeanPlusUtil.toBean(entity, getResultVOClass()));
}
/**
* 详情查询
*
* @param id 主键id
* @return 查询结果
*/
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "主键", dataType = "long", paramType = "path"),
})
@ApiOperation(value = "查询单体详情", notes = "查询单体详情")
@GetMapping("/detail")
@WebLog("'查询:' + #id")
default R<ResultVO> getDetail(@RequestParam("id") Id id) {
Entity entity = getSuperService().getById(id);
ResultVO resultVO = BeanPlusUtil.toBean(entity, getResultVOClass());
EchoService echoService = getEchoService();
if (echoService != null) {
echoService.action(resultVO);
}
return success(resultVO);
}
/**
* 批量查询
*
* @param data 批量查询
* @return 查询结果
*/
@ApiOperation(value = "批量查询", notes = "批量查询")
@PostMapping("/query")
@WebLog("批量查询")
default R<List<ResultVO>> query(@RequestBody PageQuery data) {
Entity entity = BeanPlusUtil.toBean(data, getEntityClass());
QueryWrap<Entity> wrapper = Wraps.q(entity);
List<Entity> list = getSuperService().list(wrapper);
return success(BeanPlusUtil.toBeanList(list, getResultVOClass()));
}
}
/**
* 查询Controller
*
* @param <Entity> 实体
* @param <Id> 主键
* @param <PageQuery> 分页参数
* @param <ResultVO> 实体返回VO
*/
public interface QueryController<Id extends Serializable, Entity extends SuperEntity<Id>, SaveVO, UpdateVO, PageQuery, ResultVO>
extends PageController<Id, Entity, SaveVO, UpdateVO, PageQuery, ResultVO> {
/**
* 单体查询
*
* @param id 主键id
* @return 查询结果
*/
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "主键", dataType = "long", paramType = "path"),
})
@ApiOperation(value = "单体查询", notes = "单体查询")
@GetMapping("/{id}")
@WebLog("'查询:' + #id")
default R<ResultVO> get(@PathVariable Id id) {
Entity entity = getSuperService().getById(id);
return success(BeanPlusUtil.toBean(entity, getResultVOClass()));
}
/**
* 详情查询
*
* @param id 主键id
* @return 查询结果
*/
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "主键", dataType = "long", paramType = "path"),
})
@ApiOperation(value = "查询单体详情", notes = "查询单体详情")
@GetMapping("/detail")
@WebLog("'查询:' + #id")
default R<ResultVO> getDetail(@RequestParam("id") Id id) {
Entity entity = getSuperService().getById(id);
ResultVO resultVO = BeanPlusUtil.toBean(entity, getResultVOClass());
EchoService echoService = getEchoService();
if (echoService != null) {
echoService.action(resultVO);
}
return success(resultVO);
}
/**
* 批量查询
*
* @param data 批量查询
* @return 查询结果
*/
@ApiOperation(value = "批量查询", notes = "批量查询")
@PostMapping("/query")
@WebLog("批量查询")
default R<List<ResultVO>> query(@RequestBody PageQuery data) {
Entity entity = BeanPlusUtil.toBean(data, getEntityClass());
QueryWrap<Entity> wrapper = Wraps.q(entity);
List<Entity> list = getSuperService().list(wrapper);
return success(BeanPlusUtil.toBeanList(list, getResultVOClass()));
}
}
- SaveController : 封装了保存和复制方法,并预留了 handlerSave 接口,供子类重写。
- UpdateController : 封装了修改方法,并预留了 handlerUpdate 接口,供子类重写。
抽象类
- SuperSimpleController
最简单的父类,没有任何的CRUD方法。
- SuperReadController
实现了QueryController、PageController。
- SuperWriteController
实现了SaveController、UpdateController、DeleteController。
- SuperController
实现了SaveController、UpdateController、DeleteController、QueryController、PageController。
- SuperPoiController
实现了SaveController、UpdateController、DeleteController、QueryController、PageController、PoiController。
- SuperCacheController
实现了SaveController、UpdateController、DeleteController、QueryController、PageController、PoiController。并将get、save、update、delete等方法用SuperCacheService实现
说明
业务Controller可以根据自身情况,选择继承 抽象Controller
还是 按需实现 接口Controller
.
应用分层
图中默认上层依赖于下层,箭头关系表示可直接依赖,如:开放接口层可以依赖于
Controller 层,也可以直接依赖于 Biz、Service 层,依此类推。
开放接口层:开放给其他第三方调用的接口,可直接封装Service方法暴露成PRC接口;通过Web封装成HTTP接口等
终端显示层:各个端的默认渲染层。如:模板引擎渲染、移动端展示、Vue展示等
请求处理层(Controller):主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等 。
分布式事务业务逻辑层(Biz)
说明
具于分布式事务、跨库操作(查询和写入)的业务逻辑服务层。若业务无分布式事务或跨库操作Controller可以直接调用Service层,Biz层一定不能加
@Transactional
注解,否则动态数据源跨库操作将会时效。业务逻辑层(Service):相对具体的业务逻辑服务层,只保证单个数据源本地事务。对多个Manager的组合复用。
通用处理层(Manager):通用业务处理层, 它有如下特征:
1) 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理。
2) 与 DAO 层交互,对多个 DAO 的组合复用。
3) 继承Mybatis-plus的ServiceImpl接口,封装了单表的业务操作。
数据持久层(Mapper/Dao):数据访问层,与底层 MySQL、Oracle、Hbase、OB 等进行数据交互。
缓存或第三方接口:包括其它部门 RPC 开放接口,基础平台,其它公司的 HTTP 接口。
注意
- biz的方法都是跨数据源或跨服务的且需要保证事务的
- service的save方法更加贴切实际业务,可操作多个表,并组合逻辑
- manager 的save方法只负责单个表的保存操作(如:可以对字段进行一些默认值设置)
- mapper 的insert 方法只负责原封不动的将数据插入数据库。
- 调用只能从上往下,不能反着调用,最好也不要平层调用,严禁平层交叉调用。
领域模型
- Entity: 跟数据库表一一对应
- DTO:数据传输对象,Service或Manager 使用的对象
- Query:数据查询对象,各层接收上层的查询请求。建议超过3个参数的查询进行封装。
- VO:显示层对象,Controller层接收和返回参数
Service
相对具体的业务逻辑服务层,只保证单个数据源本地事务。对多个Manager的组合复用。
SuperCacheService和SuperService的区别在于,前者的save、saveBatch、saveOrUpdateBatch、updateAllById、updateById、updateBatchById、removeById、removeByIds、getByIdCache等方法封装了缓存。
save、updateById、updateAllById等方法也提供了方法供子类重写。
java
@Override
@Transactional(rollbackFor = Exception.class)
public Entity save(SaveVO saveVO) {
Entity entity = saveBefore(saveVO);
this.getSuperManager().save(entity);
saveAfter(saveVO, entity);
return entity;
}
/**
* 保存之前处理参数等操作
*
* @param saveVO 保存VO
*/
protected Entity saveBefore(SaveVO saveVO) {
return BeanUtil.toBean(saveVO, getEntityClass());
}
/**
* 保存之后设置参数值,淘汰缓存等操作
*
* @param saveVO 保存VO
* @param entity 实体
*/
protected void saveAfter(SaveVO saveVO, Entity entity) {
}
@Override
@Transactional(rollbackFor = Exception.class)
public Entity updateById(UpdateVO updateVO) {
Entity entity = updateBefore(updateVO);
getSuperManager().updateById(entity);
updateAfter(updateVO, entity);
return entity;
}
/**
* 修改之前处理参数等操作
*
* @param updateVO 修改VO
*/
protected Entity updateBefore(UpdateVO updateVO) {
return BeanUtil.toBean(updateVO, getEntityClass());
}
/**
* 修改之后设置参数值,淘汰缓存等操作
*
* @param updateVO 修改VO
* @param entity 实体
*/
protected void updateAfter(UpdateVO updateVO, Entity entity) {
}
@Override
@Transactional(rollbackFor = Exception.class)
public Entity updateAllById(UpdateVO updateVO) {
Entity entity = updateAllBefore(updateVO);
getSuperManager().updateAllById(entity);
updateAllAfter(updateVO, entity);
return entity;
}
/**
* 修改之前处理参数等操作
*
* @param updateVO 修改VO
*/
protected Entity updateAllBefore(UpdateVO updateVO) {
return BeanUtil.toBean(updateVO, getEntityClass());
}
/**
* 修改之后设置参数值,淘汰缓存等操作
*
* @param updateVO 修改VO
* @param entity 实体
*/
protected void updateAllAfter(UpdateVO updateVO, Entity entity) {
}
@Override
@Transactional(rollbackFor = Exception.class)
public Entity save(SaveVO saveVO) {
Entity entity = saveBefore(saveVO);
this.getSuperManager().save(entity);
saveAfter(saveVO, entity);
return entity;
}
/**
* 保存之前处理参数等操作
*
* @param saveVO 保存VO
*/
protected Entity saveBefore(SaveVO saveVO) {
return BeanUtil.toBean(saveVO, getEntityClass());
}
/**
* 保存之后设置参数值,淘汰缓存等操作
*
* @param saveVO 保存VO
* @param entity 实体
*/
protected void saveAfter(SaveVO saveVO, Entity entity) {
}
@Override
@Transactional(rollbackFor = Exception.class)
public Entity updateById(UpdateVO updateVO) {
Entity entity = updateBefore(updateVO);
getSuperManager().updateById(entity);
updateAfter(updateVO, entity);
return entity;
}
/**
* 修改之前处理参数等操作
*
* @param updateVO 修改VO
*/
protected Entity updateBefore(UpdateVO updateVO) {
return BeanUtil.toBean(updateVO, getEntityClass());
}
/**
* 修改之后设置参数值,淘汰缓存等操作
*
* @param updateVO 修改VO
* @param entity 实体
*/
protected void updateAfter(UpdateVO updateVO, Entity entity) {
}
@Override
@Transactional(rollbackFor = Exception.class)
public Entity updateAllById(UpdateVO updateVO) {
Entity entity = updateAllBefore(updateVO);
getSuperManager().updateAllById(entity);
updateAllAfter(updateVO, entity);
return entity;
}
/**
* 修改之前处理参数等操作
*
* @param updateVO 修改VO
*/
protected Entity updateAllBefore(UpdateVO updateVO) {
return BeanUtil.toBean(updateVO, getEntityClass());
}
/**
* 修改之后设置参数值,淘汰缓存等操作
*
* @param updateVO 修改VO
* @param entity 实体
*/
protected void updateAllAfter(UpdateVO updateVO, Entity entity) {
}
Manager
通用业务处理层。
SuperCacheManager和SuperManager的区别在于,前者的save、saveBatch、saveOrUpdateBatch、updateAllById、updateById、updateBatchById、removeById、removeByIds、getByIdCache等方法封装了缓存。
若你继承了SuperCacheManager,子类必须重写cacheKeyBuilder方法,返回缓存key构造器。如:
java
@Override
protected CacheKeyBuilder cacheKeyBuilder() {
return new EmployeeCacheKeyBuilder();
}
@Override
protected CacheKeyBuilder cacheKeyBuilder() {
return new EmployeeCacheKeyBuilder();
}
Mapper
数据访问层。
相对于BaseMapper,增强了updateAllById、insertBatchSomeColumn方法。
提示
若你也想扩展SuperMapper中的方法,可以参考: acuitySqlInjector