Kiss架构:Springboot + Angular - Pasquale Paola

栏目: Java · 发布时间: 5年前

内容简介:就像维基百科建议的那样,KISS是一个缩写保持简单,愚蠢作为美国海军在1960年提出的设计原则.KISS原则指出,如果保持简单而不是复杂化,大多数系统都能发挥最佳作用; 因此,简单性应该是设计中的关键目标,并且应该避免不必要的复杂性。

就像维基百科建议的那样,KISS是一个缩写

保持简单,愚蠢

作为美国海军在1960年提出的设计原则.KISS原则指出,如果保持简单而不是复杂化,大多数系统都能发挥最佳作用; 因此,简单性应该是设计中的关键目标,并且应该避免不必要的复杂性。

根据我的经验,我研究了许多类型的技术,有机会检查源代码,一般来说,从客户端(可以是SPA或本机应用程序)和服务器端开发应用程序。 。依靠这样的经历,我想开发一个简单的架构,包括尊重基本的格局在CRUD上下文。我将说明这个架构的基础,作为我所有项目的起点。

在设计中我记住了KISS概念,从这个角度来看,我将提供5层,称为层,具有特定的职责任务:

  • 前端
  • API
  • 商业逻辑
  • 集成层
  • DAO

我使用多层架构模型。列表中的层顺序与信息流严格关联,从前端一直到达DAO!

本文引用的项目可通过以下链接下载: https://github.com/paspao/springboot-kiss-architecture

git clone https://github.com/paspao/springboot-kiss-architecture

该项目使用maven(即父类和子类)进行管理; 即使在Angular中开发的前端被包含在maven构建阶段中以创建单个工件(下面的FRONTEND段中提供了更多详细信息)。

为了深入了解每一层,我更喜欢使用BottomUp方法,所以让我们从数据开始。

DAO

数据访问对象。我在谈论CRUD应用程序,即要收集和处理的数据。这个模块代表了最深刻的一点。该层执行数据,它描述实体和访问逻辑。注意:插入,修改,删除和显示数据的简单数据访问逻辑,不与任何其他层绑定; 它是最深层的,并且它与它的任何兄弟都没有依赖关系,它不处理应用程序的特定方面,例如授权,事务或其他:也只是访问数据。在Springboot上下文中,我正在执行实体和存储库范例。

@Configuration
@ComponentScan(<font>"org.ska.dao"</font><font>)
@EntityScan(basePackages = {</font><font>"org.ska.dao.entity"</font><font>})
@EnableJpaRepositories(basePackages = {</font><font>"org.ska.dao.repository"</font><font>})
@EnableAutoConfiguration
@EnableTransactionManagement
<b>public</b> <b>class</b> KissDaoConfiguration {
}
</font>

所以我定义了组件,实体和存储库的位置。此外,我启用了事务,因此使用DAO模块的任何人都不必担心配置DAO模块的方面。

集成

简单的CRUD数据管理是不够的:我们可能需要与不依赖于我们数据的其他系统(例如JAX-WS或JAX-RS服务)或具有不同协议的特定打印系统等进行互操作。此组件包括所有这些交互/集成都没有对应用程序上下文的特定绑定,以保证您具有非常高的可重用性(如DAO模块,此层也是叶类型)。

@Configuration
@ComponentScan(basePackages = {<font>"org.ska.integration.beans"</font><font>})
<b>public</b> <b>class</b> KissIntegrationConfiguration {

    @Bean
    <b>public</b> GeoApiContext geocoder(){
        GeoApiContext context = <b>new</b> GeoApiContext.Builder()
                .apiKey(</font><font>"Your apikey"</font><font>)
                .build();
        <b>return</b> context;
    }
}
</font>

这里我展示了模块配置的中心点:只有一个对服务定义的引用和第三方服务的实例(GeoApiContext)。

业务逻辑

稍后识别要处理的数据时,每个应用程序必须处理定义到DAO层中的实体之间的交互逻辑。您必须将用户需求与应用程序逻辑相结合,将它们分解,然后向上层公开简单且可读的签名。因此,这一层允许开发人员进行一些处理,而无需详细说明数据库的结构或下面的集成。

我们在这里发现DTO的定义和用法有助于掩盖存储在数据库系统或各种集成bean中的数据:为什么?

有一些原因:首先,它是一种隐藏敏感数据的信息形式(例如密码,时间戳或数据一致性所需的其他信息,但对最终用户没有)。如果需要详细说明返回的数据(如从多个源组合的数据),DTO有助于以合适的方式构建这些数据。

另一个方面是数据的序列化:在某些上下文中,您必须转换数据库中存在的信息,以使其可用于人类。因此,开发人员必须“污染” 实体使用序列化逻辑,其目的应该只是表示数据,例如:数据库系统上的DATE字段可能是一个数字,但我们以可打印的方式表示它,所以我们可能会使用格式化注释; 这是一个解决方案!但在这种情况下,我们将序列化的各个方面链接到一个实体,从长远来看,这个解决方案将导致无法使用的代码。哈罗德·阿贝尔森说:

必须编写程序供人们阅读,并且只有程序才能执行。

DTO允许面对列出的问题,创建类似“缓冲区”的东西,因此更松散耦合和更多可重用性。

总而言之,BUSINESS LOGIC与DAO层和INTEGRATION层进行通信,创建协同作用并在它们之间进行交互。此外,它将逻辑和数据转换带入DTO,可供其他层使用。警告:业务逻辑层使用定义的DTO,同样适用于返回的数据。它们绝不是其他层中定义的对象,因此要确保我们上面所说的内容并且能够处理返回的数据。

该层的另一个特征是事务管理:由于它实现了业务逻辑,因此能够确定对数据的操作是否成功,因此定义了操作的“ 事务性 ”。

以下是业务逻辑层的@Configuration:

@Configuration
@ComponentScan(basePackages = {<font>"org.ska.business"</font><font>})
@Import({KissDaoConfiguration.<b>class</b>, KissIntegrationConfiguration.<b>class</b>})
<b>public</b> <b>class</b> KissBusinessConfiguration {
    
    @Bean
    <b>public</b> Mapper dozerMapper(){
        Mapper dozerBeanMapper =  DozerBeanMapperBuilder.buildDefault();
        <b>return</b> dozerBeanMapper;
    }

}
</font>

它是唯一一个直接链接到DAO和INTEGRATION层的模块,因此必须导入配置才能使用它们。此外,为了加快实体和DTO之间的映射,使用为此而生成的框架是一种很好的做法,避免了长期和不可读的setter和getter代码块; 在我的例子中,我使用了一个名为Dozer的映射框架。

API

在这层中,呈现逻辑,它代表了我们应用程序的入口点,至少从服务器的角度来看。JAX-RS或JAX-WS等服务的定义主要是以XML,JSON或其他方式呈现数据。它仅与BUSINESS LOGIC层进行对话:服务只调用Business层提供的一个或多个服务,它永远不会直接使用INTEGRATION或DAO层,也不会使用其中定义的对象,以避免紧密耦合和意大利面条代码。

它涉及身份验证和授权的管理:这里可以确定谁可以执行操作:在下面的层中要复杂得多,或者确定哪些角色尚不可知的信息。

API总是需要一些文档:缺乏REST世界之一是缺少这些服务的通用描述符。保证这方面的技术是Swagger(现在是OpenAPI):它允许记录API,但是生成的文档也可以重用来生成客户端部分,因此不仅仅是描述性的部分。例如,在我的情况下,带有REST服务的通信层完全由服务的Swagger描述生成:在FRONTEND模块中,有一个remote-services文件夹,其中包含工具: https://editor.swagger.io .

在api层的配置类中,我导入业务层并设置Swagger文档的生成。

@Configuration
@Import(KissBusinessConfiguration.<b>class</b>)
@EnableSwagger2
<b>public</b> <b>class</b> KissApiConfiguration {
    
        @Autowired
        <b>private</b> Environment env;

        @Bean
        <b>public</b> Docket api() {
            <b>return</b> <b>new</b> Docket(DocumentationType.SWAGGER_2)
                    .select()
                    <font><i>//.apis(RequestHandlerSelectors.any())</i></font><font>
                    .apis(RequestHandlerSelectors.basePackage(</font><font>"org.ska.api.web"</font><font>))
                    .paths(PathSelectors.any())
                    .build()
                    .apiInfo(apiInfo());
        }

        <b>private</b> ApiInfo apiInfo() {
            <b>return</b> <b>new</b> ApiInfo(
                    </font><font>"Contact management REST API"</font><font>,
                    </font><font>"API"</font><font>,
                    env.getProperty(</font><font>"info.version"</font><font>),
                    <b>null</b>,
                    <b>new</b> Contact(</font><font>"Pasquale Paola"</font><font>, </font><font>"https://www.linkedin.com/in/pasqualepaola/"</font><font>, </font><font>"pasquale.paola@gmail.com"</font><font>),
                    <b>null</b>, <b>null</b>, Collections.emptyList());
        }

}
</font>

前端

它代表单页应用程序:这种类型的应用程序必须与应用程序完全分离,并且Rest技术的使用已经保证了这一方面,但有必要注意与远程服务的通信是如何实现的。我经常陷入非常糟糕的组织和管理用于调用远程服务的各种HTTP客户端,我的意思是在整个应用程序中找到的引用。

为了解决这个问题并使SPA与代表与远程服务通信的所有内容严格分开,如前所述,我使用Swagger技术生成一个允许与Rest API通信的存根。所以开发人员将使用Swagger生成的东西,主要是因为它提供了大量现成的代码,具有不同的使用选项,而你不再需要重写它。此外,逻辑将在其他地方实现,因为远程通信部分(Stub)将不断重新生成,并且开发人员不会梦想在可能被覆盖的源中实现自己的逻辑(我希望)。

为了确保用Angular编写的应用程序可以包含在Maven项目的构建周期中,我确保通过添加pom.xml文件即使FRONTEND也成为Maven模块。这个模块不会产生任何工件,所以包装将是pom类型,但是这样我就可以将它插入到maven构建中并与其兄弟姐妹创建依赖关系。为了能够在Maven上下文中集成Angular构建,我使用了一个名为frontend-maven-plugin的插件:它允许安装Node和Npm实例

 <execution>
            <id>install node and npm</id>
            <goals>
              <goal>install-node-and-npm</goal>
            </goals>
            <phase>generate-resources</phase>
          </execution>
          <execution>
            <id>npm install</id>
            <goals>
              <goal>npm</goal>
            </goals>
            <configuration>
              <arguments>install</arguments>
            </configuration>
          </execution>

以及随后调用Angular CLI来管理依赖关系并构建。

 <execution>
            <id>npm build</id>
            <goals>
              <goal>npm</goal>
            </goals>
            <phase>generate-resources</phase>
            <configuration>
              <arguments>run build</arguments>
            </configuration>
          </execution>

当调用Npm构建任务时,控件将从Angular CLI中获取,如package.json中所述:

...
<font>"build"</font><font>: </font><font>"ng build --prod --progress --build-optimizer --delete-output-path --base-href /kiss/ui/ --output-path dist/resources/static/ui"</font><font>
...
</font>

输出路径设置为dist / resources / static / ui,路径dist / resources也配置为前端模块的资源。结合下面的层API配置,它允许在Springboot应用程序中注入Angular构建的结果。在输出路径(package.json 中的build命令)中有一个特殊目录  ... / static / ...,其中一个是Springboot允许定义静态内容的目录。

<resources>
    <resource>
        <directory>../frontend/dist/resources</directory>
    </resource>
    <resource>
        <directory>src/main/resources</directory>
        <filtering><b>true</b></filtering>
    </resource>
</resources>
...

Build

mvn clean install

Run​​​​​​​

java -jar api/target/api-0.0.1-SNAPSHOT.jar

访问:

http://localhost:8080/kiss/

​​​​​​​

点击标题见原文!

以上所述就是小编给大家介绍的《Kiss架构:Springboot + Angular - Pasquale Paola》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

代码之美

代码之美

Grey Wilson / 聂雪军 / 机械工业出版社 / 2008年09月 / 99.00元

《代码之美》介绍了人类在一个奋斗领域中的创造性和灵活性:计算机系统的开发领域。在每章中的漂亮代码都是来自独特解决方案的发现,而这种发现是来源于作者超越既定边界的远见卓识,并且识别出被多数人忽视的需求以及找出令人叹为观止的问题解决方案。 《代码之美》33章,有38位作者,每位作者贡献一章。每位作者都将自己心目中对于“美丽的代码”的认识浓缩在一章当中,张力十足。38位大牛,每个人对代码之美都有自......一起来看看 《代码之美》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

URL 编码/解码
URL 编码/解码

URL 编码/解码