领域驱动设计实践 —— UI层实现

 

正文

  前面几篇blog主要介绍了DDD落地架构及业务建模战术,后续几篇blog会在此基础上,讲解具体的架构实现,通过完整代码demo的形式,更好地将DDD的落地方案呈现出来。本文是架构实现讲解的第一篇,主要介绍了DDD的User Interface层的实现,详细讲解了controller、dto的职责和实现,已经UI层使用到的公共组件:CheckLogin、Loging、Validation的职责和实现细节。文末附有github地址。相比于《领域驱动设计》原书中的航运系统例子,社交服务系统的业务场景对于大家更加熟悉,相信更好理解。本文是【DDD】系列文章的其中一篇,其他可参考:使用领域驱动设计思想实现业务系统

1. User Interface

  User Interface层是用户接口层,为用户/调用方提供可访问的接口,我们简称为“UI”层。在 “【DDD】领域驱动设计实践 —— 框架实现” 一文中,我们将dto、controller归入了UI层。同时,在UI层中,我们还会去使用infrastructure层中的validation、logging、checkLogin等公共组件完成一些通用的动作。接下来我们将逐一讲解。

2. Controller

controller是公司前台

  这里的controller承担这一个请求受理的角色,就像是一个公司的前台,接受不同的请求(人员来访、电话咨询、快递/信件签收等等),必要时还会对不同的请求进行权限校验,以防坏人捣蛋(比如:查验来访者的身份,确认被访问者是否真有其人);并将不同格式的请求转换为通用的请求格式(用标准的邮件/电话/短信通知责任人);将请求转发到对应的负责人(可能是将电话转接给负责人,也可能是将应聘者介绍给面试官,还可能是叫某个程序猿出来取快递);到最后还会将来访者登录在案,必要时,还会通过前台告知具体的处理结果(告知电话咨询者其要求是否能得到满足,告知来访者他要找的人没有上班等)。

controller的职责

  类比与前台工作,我们可以发现controller有如下职责:

  •   接受请求;
  • 请求格式校验及转换;
  •   权限校验;
  •   路由请求;
  •   记录请求;
  •   回复响应;

controller的实现

  在示例代码中,我们使用spring-mvc框架实现,controller就直接使用spring-mvc中的controller层完成。对应到上述职责分别有如下组件完成:

  •   接受请求 —— Spring-MVC的DispatcherServlet组件完成;
  • 请求格式校验及转换 —— 格式校验遵循java Validation规范,使用Hibernate的validator组件完成;最终会被转换为DTO组件,并在DTO组件中落地validation,放到后面专门讲解;
  •   权限校验 —— 自实现的CheckLogin组件完成;放到后面专门讲解;
  •   路由请求 ——  Spring-MVC的@RequestMapping组件完成;
  •   记录请求 —— 自实现的Loggin组件完成;放到后面专门讲解;
  •   回复响应 —— Spring-MVC的@ResponseBody组件完成;

BaseController

  在实际编码中,发现所有的controller会有一些公共的行为,比如异常处理,封装响应dto,我们将这些行为抽象出来,放在BaseController中,所有的业务Controller继承这个基础类。

类图

代码示例

 BaseController.java
 PostController.java

3.  DTO

DTO是controller和service之间数据传输的载体

  DTO(Data Transfer Object),顾名思义,DTO用于组件/分层间传递数据,它是数据传递的载体。在这里我们用它作为 “controller <=> service”之间传递数据的载体。controller传递一个RequestDto给service,service完成业务处理后,返回一个ReponseDto。

类图

  请求中公共的属性(请求头)放置到RequestDto中。RequestDto持有一个RequestBody(请求体),包含各个场景的具体业务请求参数,所有的业务请求都会有自己的ReqBody,并继承至RequestBody。

  ResponseDto同理,不再赘述。

示例代码

 UIDto.java
 RequestDto.java
 ResponseDto
 RequestBody.java
 ResponseBody.java
 PostingReqBody.java
 PostingRespBody.java

4.  infrastructure层的公共组件

checkLogin

称职的门将

  checkLogin组件负责登录态校验,或者叫做会话控制,有时候还需要做权限校验,它是一个称职的门将。不同的部署架构对checkLogin的实现要求不一样。在传统的单体应用中,会话控制一般交给web容器来管理,通常使用filter统一管控会话,在分布式系统中,由于服务组件本身要求无会话状态,故会单独有一个SessionServer来负责会话控制。checkLogin针对上述两种不同的实现方案。

  传统的单体应用中个,直接使用filter实现,交给web容器来管理会话。对于分布式系统,则由checkLogin组件完成SessionServer的交互,接受sessionServer返回的会话校验结果,并结合当前请求的权限要求,做出相应的会话控制。

  本示例代码中未给出CheckLogin的具体实现,基本思路如上面所示。如果使用SpringMVC框架,可以使用AOP的方式,将CheckLogin以注解的方式实现,在需要进行会话控制的controller方法上,加上@CheckLogin注解。或者可以使用Spring 的HandlerInterceptor拦截器实现,可以让RequestBody实现类根据业务场景决定是否实现LoginAuthority接口,且可以根据不同的权限设置不同的LoginAuthority接口,然后在Interceptor统一做拦截处理。

类图

  采用Interceptor形式实现CheckLogin,可能的类图如下:

  UserLoginAuthority表示需要用户登录态,AccountLoginAuthority表示需要账户登录态,AccountLoginAuthority权限要求高于UserLoginAuthority。而PostingReqBody和DeletePostReqBody在所有登录态下都可以进行,因此只需实现LoginAuthority接口即可。

Logging

  Logging组件负责记录应用服务日子及关键操作日志,包括:api访问请求/响应内容、持久层访问记录、第三方服务调用记录等等。通常各个业务系统都有自己的日志组件和日志记录规范。所以本demo也不打算给出具体的代码实现。

  如果使用SpringMVC框架,可以尝试使用AOP的方式完成,可以做到对domain层无侵入,是比较友好的实践方式。

Validation

  Validation主要负责参数格式校验,确保进入到service层的参数是合法的,使入参对service更友好。

  JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解。Hibernate validator 实现了JSR303g标准,并在标准基础上对校验注解进行了扩展,主要增加了@NotEmpty注解,这在demo中有使用到。

  如何集成Hibernate validator 可以参阅如下blog:Java Bean Validation 最佳实践

  或者参考demo代码,不再赘述。

ExceptionHandler

异常都交给UI层统一处理

  ExceptionHandler是自定义的异常处理器,主要负责对service抛出的所有异常进行拦截及处理,针对不同的异常类型,转义成不同的错误码和错误提示信息返回给调用方。这样做的好处在于:让UI层之外的所有层都不再去关注exception,全部由UI层hold住,同时完成异常的统一化处理,确保exception不会漏处理,提升服务的友好性。

  demo示例中,主要有如下几类异常,项目总可以根据具体情况做扩展:

  •   BusinessException —— domain层抛出的业务领域相关异常,比如:用户访问的帖子不存在;
  •   CommunicationException —— 通讯相关异常,出现此异常,表明系统出现了故障,需要做友好提示;往往是和第三方服务交互时,第三方服务不可用或者响应超时;
  •   OutsideServiceException —— 第三方服务返回的业务异常,注意是业务异常,区别于CommunicationException在于:请求响应成功,但是业务上没能成功;比如:调用用户体系服务组件查询用户信息,用户体系服务组件返回“查无此人”;
  •   DataAccessException —— 持久层返回的数据存取相关的异常,可能是程序bug或者系统故障,需要做友好提示。

类图

5. UI层类图

6. 代码示例  

  此demo的代码已上传至github,欢迎下载和讨论,但拒绝被用于任何商业用途。

  github地址:https://github.com/daoqidelv/community-ddd-demo/tree/master

  branch:master

UI层实现的更多相关文章

  1. mvc项目架构搭建之UI层的搭建

    项目架构搭建之UI层的搭建 Contents 系列一[架构概览] 0.项目简介 1.项目解决方案分层方案 2.所用到的技术 3.项目引用关系 系列二[架构搭建初步] 4.项目架构各部分解析 5.项目创 ...

  2. 业务接口+UI层的设计(基于Castle实现的Repository)

    业务接口+UI层的设计(基于Castle实现的Repository) Repository层设计的文章见:[http://www.cnblogs.com/yomho/p/3297042.html]   ...

  3. 【Yom框架】漫谈个人框架的设计之三:业务接口+UI层的设计(基于Castle实现的Repository)

    Repository层设计的文章见:[http://www.cnblogs.com/yomho/p/3297042.html]   一.概要设计 上面Reposity 应该为 Repository 特 ...

  4. 【DDD】领域驱动设计实践 —— UI层实现

    前面几篇blog主要介绍了DDD落地架构及业务建模战术,后续几篇blog会在此基础上,讲解具体的架构实现,通过完整代码demo的形式,更好地将DDD的落地方案呈现出来.本文是架构实现讲解的第一篇,主要 ...

  5. Spring.NET在MVC中实现业务层和UI层解耦

    最近在项目中用到了Spring.NET,使用它来实现业务层和UI层解耦.使用过程中难免遇到问题,现把遇到的一些问题整理出来,留作笔记. 使用的开发工具是vs2017,.netframework 4.6 ...

  6. 如何实现UI层的松耦合

    UI层的松耦合主要是指html.css.js的松耦合 1.  将js代码从css中分离,即不使用expression 2.  将css从js中分离,尽量不要在js中直接操作css.如果需要操作,可以使 ...

  7. UI层自动化测试介绍

    UI指的是用户可以用肉眼可以看到的页面. UI层自动化测试的原理.不论是web端还是移动端,原理都是一样的,就是基于页面元素的识别和定位来进行模拟用户行为. 首先识别到某个元素,比如一个按钮,然后定义 ...

  8. NGUI发布后UI层看不见的解决办法

    NGUI发布后UI层看不见的解决办法 提示信息:You can'tplace widgets on a layer different than the UIPanel that manages th ...

  9. 20140117-配置文件为什么放在UI层

    配置文件为什么放在UI层 (刚才写着代码突然忘了配置文件为什么要放在UI层了,只记得晓虎老师强调过.找了半天视频……) 现总结一下: 晓虎老师给出的理由,大体如下:比如一个web项目,分成三层,DAL ...

随机推荐

  1. Ubuntu 下常用的命令 简略记录

    # 动态显示 NVIDIA watch -n 1 nvidia-smi #查看某一目录下文件的总数(不包含子目录) ls -l | wc -l #挂载硬盘或者U盘 mount /dev/sdb1 /m ...

  2. 存储器的保护(二)——《x86汇编语言:从实模式到保护模式》读书笔记19

    接着上一篇博文说. 5.代码段执行时的保护 每个代码段都有自己的段界限.同栈段一个道理,有效界限和G位相关. G=0:有效界限 = 描述符中的段界限 G=1:有效界限 = 描述符中的段界限值 * 0x ...

  3. vue打包后运行在本地/非服务器端环境的访问路径

    vue打包前的配置: 项目目录下--> config文件夹---> index.js: build:  { assetsPublickPath:  './',   // 设置成相对路径   ...

  4. 记一次走心One 2 One沟通

    聊的比较零零碎碎,内容比较散,有些solution不错,记一些要点吧(1)要学会汇报,就是坐你身边的人,也未必知道你在干啥 三个人都在砌墙.当人们分别问他们在做什么,他们的答案却不一样:第一个人头也没 ...

  5. 限流(三)Redis + lua分布式限流

    一.简介 1)分布式限流 如果是单实例项目,我们使用Guava这样的轻便又高性能的堆缓存来处理限流.但是当项目发展为多实例了以后呢?这时候我们就需要采用分布式限流的方式,分布式限流可以以redis + ...

  6. shodan在渗透测试中的应用

    场景1:想搜索美国所有的elasticsearch服务器 ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口.设计 ...

  7. zookeeper【6】负载均衡

    负载均衡是一种手段,用来把对某种资源的访问分摊给不同的设备,从而减轻单点的压力. 架构图 图中左侧为ZooKeeper集群,右侧上方为工作服务器,下面为客户端.每台工作服务器在启动时都会去zookee ...

  8. QQ 聊天机器人小薇 2.0.0 发布!

    本次发布主要加入了支持讨论组聊天,并增强了稳定性.另外,官方小薇 QQ 机器人已经下线,大家要体验的话请 自建私服~ 简介 XiaoV(小薇)是一个用 Java 写的 QQ 聊天机器人 Web 服务, ...

  9. GetVersion和GetVersionEx

    原文:http://www.cnblogs.com/VOIP/archive/2011/03/22/1990927.html Windows API 中有两个函数可以得到系统版本信息:GetVersi ...

  10. visual studio code断点调试react

    在项目配置文件   .vscode\launch.json 中添加:   "sourceMaps": true,   "skipFiles": [   &quo ...