接上篇:https://developer.aliyun.com/article/1228260?spm=a2c6h.13148508.setting.28.6e864f0ezvytvj
四、 把数据库模型类暴露给接口
现象描述:
上面的代码,看上去是满足SpringMVC服务端三层架构的,唯一的问题就是把数据库模型类UserDO直接暴露给了外部接口。
1. 存在问题及解决方案
1) 存在问题
• 间接暴露数据库表格设计,给竞争对手竞品分析带来方便;
• 如果数据库查询不做字段限制,会导致接口数据庞大,浪费用户的宝贵流量;
• 如果数据库查询不做字段限制,容易把敏感字段暴露给接口,导致出现数据的安全问题;
• 如果数据库模型类不能满足接口需求,需要在数据库模型类中添加别的字段,导致数据库模型类跟数据库字段不匹配问题;
• 如果没有维护好接口文档,通过阅读代码是无法分辨出数据库模型类中哪些字段是接口使用的,导致代码的可维护性变差。
2) 解决方案
• 从管理制度上要求数据库和接口的模型类完全独立;
• 从项目结构上限制开发人员把数据库模型类暴露给接口。
2. 项目搭建的三种方式
下面,将介绍如何更科学地搭建Java项目,有效地限制开发人员把数据库模型类暴露给接口。
第1种:共用模型的项目搭建
共用模型的项目搭建,把所有模型类放在一个模型项目(example-model)中,其它项目(example-repository、example-service、example-website)都依赖该模型项目,关系图如下:
• 风险
表现层项目(example-webapp)可以调用业务层项目(example-service)中的任意服务函数,甚至于越过业务层直接调用持久层项目(example-repository)的DAO函数。
第2种:模型分离的项目搭建
模型分离的项目搭建,单独搭建API项目(example-api),抽象出对外接口及其模型VO类。业务层项目(example-service)实现了这些接口,并向表现层项目(example-webapp)提供服务。表现层项目(example-webapp)只调用API项目(example-api)定义的服务接口。
• 风险
表现层项目(example-webapp)仍然可以调用业务层项目(example-service)提供的内部服务函数和持久层项目(example-repository)的DAO函数。为了避免这种情况,只好管理制度上要求表现层项目(example-webapp)只能调用API项目(example-api)定义的服务接口函数。
第3种:服务化的项目搭建
服务化的项目搭,就是把业务层项目(example-service)和持久层项目(example-repository)通过Dubbo项目(example-dubbo)打包成一个服务,向业务层项目(example-webapp)或其它业务项目(other-service)提供API项目(example-api)中定义的接口函数。
说明:
Dubbo项目(example-dubbo)只发布API项目(example-api)中定义的服务接口,保证了数据库模型无法暴露。业务层项目(example-webapp)或其它业务项目(other-service)只依赖了API项目(example-api),只能调用该项目中定义的服务接口。
3. 一条不太建议的建议
有人会问:接口模型和持久层模型分离,接口定义了一个查询数据模型VO类,持久层也需要定义一个查询数据模型DO类;接口定义了一个返回数据模型VO类,持久层也需要定义一个返回数据模型DO类……这样,对于项目早期快速迭代开发非常不利。能不能只让接口不暴露持久层数据模型,而能够让持久层使用接口的数据模型?
如果从SpringMVC服务端三层架构来说,这是不允许的,因为它会影响三层架构的独立性。但是,如果从快速迭代开发来说,这是允许的,因为它并不会暴露数据库模型类。所以,这是一条不太建议的建议。
后记
“仁者见仁、智者见智”,每个人都有自己的想法,而文章的内容也只是我的一家之言。
谨以此文献给那些我工作过的创业公司,是您们曾经放手让我去整改乱象,让我从中受益颇深并得以技术成长。