当前位置: 首页 > news >正文

河南旅游集团 网站建设百度号码认证平台官网首页

河南旅游集团 网站建设,百度号码认证平台官网首页,网站制作厦门公司,工作5年判若两人1、分层思想 计算机领域有一句话:计算机中任何问题都可通过增加一个虚拟层解决。这句体现了分层思想重要性,分层思想同样适用于Java工程架构。 分层优点是每层只专注本层工作,可以类比设计模式单一职责原则,或者经济学比较优势原…

1、分层思想

计算机领域有一句话:计算机中任何问题都可通过增加一个虚拟层解决。这句体现了分层思想重要性,分层思想同样适用于Java工程架构。

分层优点是每层只专注本层工作,可以类比设计模式单一职责原则,或者经济学比较优势原理,每层只做本层最擅长的事情。

分层缺点是层之间通信时,需要通过适配器,翻译成本层或者下层可以理解的信息,通信成本有所增加。

工程分层需要从五个维度思考:

(1) 单一
每层只处理一类事情,满足单一职责原则

(2) 降噪
信息在每一层进行传输,满足最小知识原则,只向下层传输必要信息

(3) 适配
每层都需要一个适配器,翻译信息为本层或者下层可以理解的信息

(4) 业务
业务对象可以整合业务逻辑,例如使用充血模型整合业务

(5) 数据
数据对象尽量纯净,尽量不要聚合业务

1.2 九层结构
综上所述SpringBoot工程可以分为九层:

工具层:util
整合层:integration
基础层:infrastructure
服务层:service
领域层:domain
门面层:facade
控制层:controller
客户端:client
启动层:boot

2、 分层详解

创建测试项目user-demo-service:

user-demo-service-user-demo-service-boot-user-demo-service-client-user-demo-service-controller-user-demo-service-domain-user-demo-service-facade-user-demo-service-infrastructure-user-demo-service-integration-user-demo-service-service-user-demo-service-util

2.1 util

  • 工具层承载工具代码

  • 不依赖本项目其它模块

  • 只依赖一些通用工具包

user-demo-service-util-/src/main/java-date-DateUtil.java-json-JSONUtil.java-validate-BizValidator.java

2.2 infrastructure
基础层核心是承载数据访问,entity实体对象承载在本层。

2.2.1 项目结构
代码层分为两个领域:

  • player:运动员
  • game:比赛

每个领域具有两个子包:

  • entity
  • mapper

user-demo-service-infrastructure-/src/main/java-player-entity-PlayerEntity.java-mapper-PlayerEntityMapper.java-game-entity-GameEntity.java-mapper-GameEntityMapper.java-/src/main/resources-mybatis-sqlmappers-gameEntityMapper.xml-playerEntityMapper.xml

2.2.2 本项目间依赖关系
infrastructure只依赖工具模块

<dependency><groupId>com.test.javafront</groupId><artifactId>user-demo-service-util</artifactId>
</dependency>

2.2.3 核心代码
创建运动员数据表:

CREATE TABLE `player` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',`player_id` varchar(256) NOT NULL COMMENT '运动员编号',`player_name` varchar(256) NOT NULL COMMENT '运动员名称',`height` int(11) NOT NULL COMMENT '身高',`weight` int(11) NOT NULL COMMENT '体重',`game_performance` text COMMENT '最近一场比赛表现',`creator` varchar(256) NOT NULL COMMENT '创建人',`updator` varchar(256) NOT NULL COMMENT '修改人',`create_time` datetime NOT NULL COMMENT '创建时间',`update_time` datetime NOT NULL COMMENT '修改时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

运动员实体对象,gamePerformance字段作为string保存在数据库,这体现了数据层尽量纯净,不要整合过多业务,解析任务应该放在业务层:

public class PlayerEntity {private Long id;private String playerId;private String playerName;private Integer height;private Integer weight;private String creator;private String updator;private Date createTime;private Date updateTime;private String gamePerformance;
}

运动员Mapper对象:

@Repository
public interface PlayerEntityMapper {int insert(PlayerEntity record);int updateById(PlayerEntity record);PlayerEntity selectById(@Param("playerId") String playerId);
}

2.3 domain
2.3.1 概念说明
领域层是DDD流行兴起之概念

可以通过三组对比理解领域层

  • 领域对象 VS 数据对象
  • 领域对象 VS 业务对象
  • 领域层 VS 业务层

(1) 领域对象 VS 数据对象
数据对象字段尽量纯净,使用基本类型

public class PlayerEntity {private Long id;private String playerId;private String playerName;private Integer height;private Integer weight;private String creator;private String updator;private Date createTime;private Date updateTime;private String gamePerformance;
}

以查询结果领域对象为例

领域对象需要体现业务含义

public class PlayerQueryResultDomain {private String playerId;private String playerName;private Integer height;private Integer weight;private GamePerformanceVO gamePerformance;
}
public class GamePerformanceVO {// 跑动距离private Double runDistance;// 传球成功率private Double passSuccess;// 进球数private Integer scoreNum;
}

(2) 领域对象 VS 业务对象
业务对象同样会体现业务,领域对象和业务对象有什么不同呢?其中一个最大不同是领域对象采用充血模型聚合业务。

运动员新增业务对象:

public class PlayerCreateBO {private String playerName;private Integer height;private Integer weight;private GamePerformanceVO gamePerformance;private MaintainCreateVO maintainInfo;
}

运动员新增领域对象:

public class PlayerCreateDomain implements BizValidator {private String playerName;private Integer height;private Integer weight;private GamePerformanceVO gamePerformance;private MaintainCreateVO maintainInfo;@Overridepublic void validate() {if (StringUtils.isEmpty(playerName)) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (null == height) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (height > 300) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (null == weight) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (null != gamePerformance) {gamePerformance.validate();}if (null == maintainInfo) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}maintainInfo.validate();}
}

(3) 领域层 VS 业务层
领域层和业务层都包含业务,二者不是替代关系,而是互补关系。业务层可以更加灵活组合不同领域业务,并且可以增加流控、监控、日志、权限,分布式锁等控制,相较于领域层功能更为丰富。

2.3.2 项目结构
代码层分为两个领域:

  • player:运动员
  • game:比赛

每个领域具有三个子包:

  • domain:领域对象
  • event:领域事件
  • vo:值对象
user-demo-service-domain-/src/main/java-base-domain-BaseDomain.java-event-BaseEvent.java-vo-BaseVO.java-MaintainCreateVO.java-MaintainUpdateVO.java-player-domain-PlayerCreateDomain.java-PlayerUpdateDomain.java-PlayerQueryResultDomain.java-event-PlayerUpdateEvent.java-vo-GamePerformanceVO.java-game-domain-GameCreateDomain.java-GameUpdateDomain.java-GameQueryResultDomain.java-event-GameUpdateEvent.java-vo-GameSubstitutionVO.java

2.3.3 本项目间依赖关系
domain依赖本项目两个模块:

  • util
  • client

之所以依赖client模块是因为领域对象聚合了业务校验,以下信息需要暴露至外部:

  • BizException
  • ErrorCodeBizEnum
<dependency><groupId>com.test.javafront</groupId><artifactId>user-demo-service-util</artifactId>
</dependency>
<dependency><groupId>com.test.javafront</groupId><artifactId>user-demo-service-client</artifactId>
</dependency>

2.3.4 核心代码
以运动员修改领域对象为例:

// 运动员修改领域对象

public class PlayerUpdateDomain extends BaseDomain implements BizValidator {private String playerId;private String playerName;private Integer height;private Integer weight;private String updator;private Date updatetime;private GamePerformanceVO gamePerformance;private MaintainUpdateVO maintainInfo;@Overridepublic void validate() {if (StringUtils.isEmpty(playerId)) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (StringUtils.isEmpty(playerName)) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (null == height) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (height > 300) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (null == weight) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (null != gamePerformance) {gamePerformance.validate();}if (null == maintainInfo) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}maintainInfo.validate();}
}

// 比赛表现值对象

public class GamePerformanceVO implements BizValidator {// 跑动距离private Double runDistance;// 传球成功率private Double passSuccess;// 进球数private Integer scoreNum;@Overridepublic void validate() {if (null == runDistance) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (null == passSuccess) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (Double.compare(passSuccess, 100) > 0) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (null == runDistance) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (null == scoreNum) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}}
}

// 修改人值对象

public class MaintainUpdateVO implements BizValidator {// 修改人private String updator;// 修改时间private Date updateTime;@Overridepublic void validate() {if (null == updator) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}if (null == updateTime) {throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);}}
}

2.4 service
2.4.1 项目结构

user-demo-service-service-/src/main/java-player-adapter-PlayerServiceAdapter.java-event-PlayerMessageSender.java-service-PlayerService.java-game-adapter-GameServiceAdapter.java-event-GameMessageSender.java-service-GameService.java

2.4.2 本项目间依赖关系
service依赖本项目四个模块:

  • util
  • domain
  • integration
  • infrastructure
<dependency><groupId>com.test.javafront</groupId><artifactId>user-demo-service-domain</artifactId>
</dependency>
<dependency><groupId>com.test.javafront</groupId><artifactId>user-demo-service-infrastructure</artifactId>
</dependency>
<dependency><groupId>com.test.javafront</groupId><artifactId>user-demo-service-util</artifactId>
</dependency>
<dependency><groupId>com.test.javafront</groupId><artifactId>user-demo-service-integration</artifactId>
</dependency>

2.4.3 核心代码
以运动员编辑服务为例:

// 运动员服务

public class PlayerService {@Resourceprivate PlayerEntityMapper playerEntityMapper;@Resourceprivate PlayerMessageSender playerMessageSender;@Resourceprivate PlayerServiceAdapter playerServiceAdapter;public boolean updatePlayer(PlayerUpdateDomain player) {AssertUtil.notNull(player, new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT));player.validate();PlayerEntity entity = playerServiceAdapter.convertUpdate(player);playerEntityMapper.updateById(entity);playerMessageSender.sendPlayerUpdatemessage(player);return true;}
}

// 运动员消息服务

public class PlayerMessageSender {@Resourceprivate PlayerServiceAdapter playerServiceAdapter;public boolean sendPlayerUpdatemessage(PlayerUpdateDomain domain) {PlayerUpdateEvent event = playerServiceAdapter.convertUpdateEvent(domain);log.info("sendPlayerUpdatemessage event={}", event);return true;}
}

// 服务适配器

public class PlayerServiceAdapter {// domain -> entitypublic PlayerEntity convertUpdate(PlayerUpdateDomain domain) {PlayerEntity player = new PlayerEntity();player.setPlayerId(domain.getPlayerId());player.setPlayerName(domain.getPlayerName());player.setWeight(domain.getWeight());player.setHeight(domain.getHeight());if (null != domain.getGamePerformance()) {player.setGamePerformance(JacksonUtil.bean2Json(domain.getGamePerformance()));}String updator = domain.getMaintainInfo().getUpdator();Date updateTime = domain.getMaintainInfo().getUpdateTime();player.setUpdator(updator);player.setUpdateTime(updateTime);return player;}// domain -> eventpublic PlayerUpdateEvent convertUpdateEvent(PlayerUpdateDomain domain) {PlayerUpdateEvent event = new PlayerUpdateEvent();event.setPlayerUpdateDomain(domain);event.setMessageId(UUID.randomUUID().toString());event.setMessageId(PlayerMessageType.UPDATE.getMsg());return event;}
}

2.5 intergration
本项目可能会依赖外部服务,那么将外部DTO转换为本项目可以理解的对象,需要在本层处理。

2.5.1 项目结构
假设本项目调用了用户中心服务:

user-demo-service-intergration-/src/main/java-user-adapter-UserClientAdapter.java-proxy-UserClientProxy.java

2.5.2 本项目间依赖关系
intergration依赖本项目两个模块:

  • util
  • domain
    之所以依赖domain模块,是因为本层需要将外部DTO转换为本项目可以理解的对象,这些对象就放在domain模块。
<dependency><groupId>com.test.javafront</groupId><artifactId>user-demo-service-domain</artifactId>
</dependency>
<dependency><groupId>com.test.javafront</groupId><artifactId>user-demo-service-util</artifactId>
</dependency>

2.5.3 核心代码
现在我们将外部对象UserClientDTO

转换为本项目领域对象UserInfoDomain

(1) 外部服务
// 外部对象

public class UserInfoClientDTO implements Serializable {private String id;private String name;private Date createTime;private Date updateTime;private String mobile;private String cityCode;private String addressDetail;
}

// 外部服务

public class UserClientService {// RPC模拟public UserInfoClientDTO getUserInfo(String userId) {UserInfoClientDTO userInfo = new UserInfoClientDTO();userInfo.setId(userId);userInfo.setName(userId);userInfo.setCreateTime(DateUtil.now());userInfo.setUpdateTime(DateUtil.now());userInfo.setMobile("test-mobile");userInfo.setCityCode("test-city-code");userInfo.setAddressDetail("test-address-detail");return userInfo;}
}

(2) 本项目领域对象
domain模块新增user领域:

user-demo-service-domain-/src/main/java-user-domain-UserDomain.java-vo-UserAddressVO.java-UserContactVO.java

user领域对象代码:

// 用户领域

public class UserInfoDomain extends BaseDomain {private UserContactVO contactInfo;private UserAddressVO addressInfo;
}

// 地址值对象

public class UserAddressVO extends BaseVO {private String cityCode;private String addressDetail;
}

// 联系方式值对象

public class UserContactVO extends BaseVO {private String mobile;
}

(3) 适配器

public class UserClientAdapter {// third dto -> domainpublic UserInfoDomain convertUserDomain(UserInfoClientDTO userInfo) {UserInfoDomain userDomain = new UserInfoDomain();UserContactVO contactVO = new UserContactVO();contactVO.setMobile(userInfo.getMobile());userDomain.setContactInfo(contactVO);UserAddressVO addressVO = new UserAddressVO();addressVO.setCityCode(userInfo.getCityCode());addressVO.setAddressDetail(userInfo.getAddressDetail());userDomain.setAddressInfo(addressVO);return userDomain;}
}

(4) 调用外部服务

public class UserClientProxy {@Resourceprivate UserClientService userClientService;@Resourceprivate UserClientAdapter userClientAdapter;public UserInfoDomain getUserInfo(String userId) {UserInfoClientDTO user = userClientService.getUserInfo(userId);UserInfoDomain result = userClientAdapter.convertUserDomain(user);return result;}
}

2.6 facade + client
设计模式中有一种Facade模式,称为门面模式或者外观模式。这种模式提供一个简洁对外语义,屏蔽内部系统复杂性。

client承载数据对外传输对象DTO,facade承载对外服务,这两层必须满足最小知识原则,无关信息不必对外透出。

这样做有两个优点:

  • 简洁性:对外服务语义明确简洁
  • 安全性:敏感字段不能对外透出

2.6.1 项目结构
(1) client
user-demo-service-client

   -/src/main/java-base-dto-BaseDTO.java-error-BizException.java-BizErrorCode.java-event-BaseEventDTO.java-result-ResultDTO.java-player-dto-PlayerCreateDTO.java-PlayerQueryResultDTO.java-PlayerUpdateDTO.java-enums-PlayerMessageTypeEnum.java-event-PlayerUpdateEventDTO.java-service-PlayerClientService.java

(2) facade
user-demo-service-facade

-/src/main/java-player-adapter-PlayerFacadeAdapter.java-impl-PlayerClientServiceImpl.java-game-adapter-GameFacadeAdapter.java-impl-GameClientServiceImpl.java

2.6.2 本项目间依赖关系
client不依赖本项目其它模块,这一点非常重要,因为client会被外部引用,必须保证这一层简洁和安全。

facade依赖本项目三个模块:

  • domain
  • client
  • service
<dependency><groupId>com.test.javafront</groupId><artifactId>user-demo-service-domain</artifactId>
</dependency>
<dependency><groupId>com.test.javafront</groupId><artifactId>user-demo-service-client</artifactId>
</dependency>
<dependency><groupId>com.test.javafront</groupId><artifactId>user-demo-service-service</artifactId>
</dependency>

2.6.3 核心代码
(1) DTO
以查询运动员信息为例,查询结果DTO只封装最关键字段,例如运动员ID、创建时间、修改时间等业务不强字段就无须透出:

public class PlayerQueryResultDTO implements Serializable {private String playerName;private Integer height;private Integer weight;private GamePerformanceDTO gamePerformanceDTO;
}

(2) 客户端服务

public interface PlayerClientService {public ResultDTO<PlayerQueryResultDTO> queryById(String playerId);
}

(3) 适配器

public class PlayerFacadeAdapter {// domain -> dtopublic PlayerQueryResultDTO convertQuery(PlayerQueryResultDomain domain) {if (null == domain) {return null;}PlayerQueryResultDTO result = new PlayerQueryResultDTO();result.setPlayerId(domain.getPlayerId());result.setPlayerName(domain.getPlayerName());result.setHeight(domain.getHeight());result.setWeight(domain.getWeight());if (null != domain.getGamePerformance()) {GamePerformanceDTO performance = convertGamePerformance(domain.getGamePerformance());result.setGamePerformanceDTO(performance);}return result;}
}

(4) 服务实现

public class PlayerClientServiceImpl implements PlayerClientService {@Resourceprivate PlayerService playerService;@Resourceprivate PlayerFacadeAdapter playerFacadeAdapter;@Overridepublic ResultDTO<PlayerQueryResultDTO> queryById(String playerId) {PlayerQueryResultDomain resultDomain = playerService.queryPlayerById(playerId);if (null == resultDomain) {return ResultCommonDTO.success();}PlayerQueryResultDTO result = playerFacadeAdapter.convertQuery(resultDomain);return ResultCommonDTO.success(result);}
}

2.7 controller
facade服务实现可以作为RPC提供服务,controller则作为本项目HTTP接口提供服务,供前端调用。

controller需要注意HTTP相关特性,敏感信息例如登陆用户ID不能依赖前端传递,登陆后前端会在请求头带一个登陆用户信息,服务端需要从请求头中获取并解析。

2.7.1 项目结构

user-demo-service-controller-/src/main/java-config-CharsetConfig.java-controller-player-PlayerController.java-game-GameController.java

2.7.2 本项目依赖关系
controller依赖本项目一个模块:

facade
根据依赖传递原理同时依赖以下模块:

  • domain
  • client
  • service
<dependency><groupId>com.test.javafront</groupId><artifactId>user-demo-service-facade</artifactId>
</dependency>

2.7.3 核心代码

@RestController
@RequestMapping("/player")
public class PlayerController {@Resourceprivate PlayerClientService playerClientService;@PostMapping("/add")public ResultDTO<Boolean> add(@RequestHeader("test-login-info") String loginUserId, @RequestBody PlayerCreateDTO dto) {dto.setCreator(loginUserId);ResultCommonDTO<Boolean> resultDTO = playerClientService.addPlayer(dto);return resultDTO;}@PostMapping("/update")public ResultDTO<Boolean> update(@RequestHeader("test-login-info") String loginUserId, @RequestBody PlayerUpdateDTO dto) {dto.setUpdator(loginUserId);ResultCommonDTO<Boolean> resultDTO = playerClientService.updatePlayer(dto);return resultDTO;}@GetMapping("/{playerId}/query")public ResultDTO<PlayerQueryResultDTO> queryById(@RequestHeader("test-login-info") String loginUserId, @PathVariable("playerId") String playerId) {ResultCommonDTO<PlayerQueryResultDTO> resultDTO = playerClientService.queryById(playerId);return resultDTO;}
}

2.8 boot
boot作为启动层,只有启动入口代码

2.8.1 项目结构
所有模块代码均必须属于com.user.demo.service子路径

user-demo-service-boot-/src/main/java-com.user.demo.service-MainApplication.java

2.8.2 本项目间依赖
boot引用本项目所有模块

  • util
  • integration
  • infrastructure
  • service
  • domain
  • facade
  • controller
  • client

2.8.3 核心代码

@MapperScan("com.user.demo.service.infrastructure.*.mapper")
@SpringBootApplication
public class MainApplication {public static void main(final String[] args) {SpringApplication.run(MainApplication.class, args);}
}
http://www.hkea.cn/news/769712/

相关文章:

  • 提供网站制作公司哪家好网络软文范文
  • 做原型网站枣庄网络推广seo
  • 品牌网站开发设计外贸网站平台
  • 网站做留言板网站推广在线
  • 长春服务好的网络营销seo网站推广的主要目的
  • 搜索引擎优化和关键词竞价广告的区别宿州百度seo排名软件
  • 一搜同志网站建设电话青岛网站seo优化
  • 官方做任务网站网络营销公司注册找哪家
  • django做视频网站网络营销推广专家
  • 国外手做网站搜索引擎推广的关键词
  • 网站建设商标注册多少类目域名注册免费
  • 哪里有网站设计公司长沙网络公司最新消息
  • 试描述一下网站建设的基本流程百度怎么发布短视频
  • 我现在有域名怎么做网站搜索关键词热度
  • 海外如何 淘宝网站建设快速seo整站优化排行
  • 代还信用卡网站建设赣州seo顾问
  • 响应式网站建设推广开网店
  • 成都专业网站推广公司优化大师优化项目有
  • 怎么用wordpress搭建网站百度关键词排名点
  • 外挂网站模板域名搜索引擎入口
  • 手机网站开发 pdfseo搜索引擎优化工作内容
  • 上海中小网站建设洛阳seo博客
  • 南宁网站建设公司哪家专业搜索引擎优化包括
  • 新疆住房与建设厅网站新产品推广方式有哪些
  • 做网站站怎么赚钱网络营销模式有哪些?
  • 南通城市建设集团有限公司网站南京谷歌推广
  • 南通网站定制方案怎么查找关键词排名
  • 权大师的网站是哪个公司做的百度做个人简介多少钱
  • 烟台网站建设设计软文广告经典案例100字
  • 做微信用什么网站广州百度seo代理