项目领域模型的应用
1.领域对象的使用
用于项目不同层次间的数据交互,并可以在不同层次中实现转换;
所有的领域对象建议使用贫血模型;
领域对象的使用会使得类数量增多;
2.常见的几种领域对象
PO(Persistent Object)持久对象 / Entity一般相当于对应着数据模型(数据库)。其中一种可以看成是Java对象,并且与数据库中的表相映射;同时,在PO中不应该包含任何对数据库的操作。
DO(Domain Object)领域对象:通过提炼现实世界中的核心要素而形成的实体或虚拟概念,在大多数情况下它能够与特定的Product Object(PO)实现一一对应的关系。然而,在某些复杂场景下,一个DO可能会代表多个PO之间的交互关系(如业务流程中的关联性)。
3.DTO(Data Transfer Object)作为数据传输实体,在展示及API层与服务端之间扮演着重要角色。
在Web开发中, VO(View Object)代表显示层对象.它位于展示层中,并负责将特定页面或组件的所有数据整合到一个统一返回对象Result
5.QUERY: 查询对象,用于数据访问层。
常用的有:po/entity, dto, query
3.项目分层
(摘自阿里开发规范)

4.各层的领域对象

5.项目分包结构
web, api, service, dal
+---zhku-dal
| +---src\main\java\com\zhku\computer
| | | +---entity
| | | +---po
| | | +---manager
| | | +---mapper
| | | +---config
| | | +---enum
| | | /---resource
| | | +---xml
+---zhku-service
| +---src\main\java\com\zhku\computer
| | | +---impl
| | | +---remote
| | | +---convert
| | | +---util
+---zhku-service-api
| +---src\main\java\com\zhku\computer
| | | \---api
| | | +---service
| | | +---query
| | | +---dto
| | | +---exception
\---zhku-web
| +---src\main\java\com\zhku\computer
| | | \---web
| | | +---config
| | | +---api
| | | +---route
| | | +---mobile
代码解读
| web层 | UserController |
|---|---|
| 领域对象 | query, dto |
@PostMapping(value = "/v1/school/{userId}")
public ZHKUResult<UserDto> saveUser(@Validated UserSaveQuery query) {
userService.saveUser(query);
return new ZHKUResult<>();
}
@DeleteMapping(value = "/v1/school/{userId}")
public ZHKUResult removeUser(@Validated UserQuery query) {
userService.removeUser(query);
return new ZHKUResult();
}
@PutMapping(value = "/v1/school/{userId}")
public ZHKUResult<UserDto> updateUser(@Validated UserSaveQuery query) {
userService.updateUser(query);
return new ZHKUResult();
}
@GetMapping(value = "/v1/school/{userId}")
public ZHKUResult<UserDto> findUser(@Validated UserQuery query) {
return new ZHKUResult<UserDto>(userService.findUser(query));
}
代码解读
| service-api层 | UserService |
|---|---|
| 领域对象 | query, dto |
void saveUser(UserSaveQuery query);
void removeUser(UserQuery query)
void updateUser(UserSaveQuery query)
UserDto findUser(UserQuery query)
代码解读
| service层 | UserServiceImpl |
|---|---|
| 领域对象 | query, dto, po/entity |
void saveUser(UserSaveQuery query){
systemService.validated(query); //other service api, exp: dubbo api / http api
UserEntity user = convert.toUserEntity(query);
userManager.saveUser(user);
}
void deleteUser(UserQuery query){
String userId = query.getUserId();
userManager.deleteUser(userId);
}
void updateUser(usersaveQuery query){
UserEntity user = convert.toUserEntity(query);
userManager.updateUser(user);
}
UserDto findUser(UserQuery query){
String userId = query.getUserId();
UserEntity user = userManager.findUser(userId);
return convert.toUserDto(user);
}
代码解读
| dal-manager层 | userManager |
|---|---|
| 领域对象 | po/entity |
void saveUser(UserEntity user){
userMapper.saveUser(user);
}
void deleteUser(String userId){
userMapper.deleteUser(userId);
}
void updateUser(UserEntity user){
userMapper.updateUser(user);
}
UserEntity findUser(String userId){
return userMapper.findUser(userId);
}
代码解读
| dal层 | UserMapper |
|---|---|
| 领域对象 | po/entity |
void saveUser(@Param("user") UserEntity user);
void deleteUser(@Param("userId") String userId);
void updateUser(@Param("user")UserEntity user);
UserEntity findUser(@Param("userId")String userId);
代码解读
域外对象转码工具:MapStruct(在实际应用中遇到部分字段无法完成转码的问题,请手动编写默认方法以解决转码问题,并安装IDEA中的GenerateAllSetter插件),或者采用ShallowCopyBeanUtils.copyProperties(该方法有两个主要限制条件:一是对两个要进行转码的对象有要求;二是从性能上受到了影响)
实践规约
各模块之间的层级结构中不允许出现跨层次或逆向的引用关系;例如:web layer → API layer → service layer → service/manager layer → DAL;
在同层级之间只能进行单向引用而禁止循环引用。例如,在服务架构中,A服务已经调用了B服务,因此B服务就不能再调用A服务
3. Controller层统一独立抽出放置网关中,所有的参数校验放在网关层;
4. Service层只能注入DAO(不建议),Manager层的依赖;
5. po/entity不可在web层,api层中暴露,系统对外提供的领域对象为dto;
6. 尽量每个请求使用不同的query;
7.dto需要实现序列化接口;
