为什么从 MVC 到 DDD,架构的本质是什么?

news2024/12/29 10:53:40

作者:小傅哥

博客:https://bugstack.cn

沉淀、分享、成长,让自己和他人都能有所收获!😄

本文来自于小傅哥新编写的 《Java简明教程》 系列内容,本教程意在于通过简单、明了、清晰的成体系内容,教会Java学习伙伴,可以在学习后能进行Java项目开发。

今天要分享的是 MVC 和 DDD 的架构本质,通过由浅入深的介绍讲解和视频带着手把手操作创建工程架构。让无论是学习 MVC 的小白码农还是希望了解更多关于 DDD 内容的老白码农,都可以学习到一点自己需要的内容。

一、MVC 架构

如果我们尝试把编程的复杂架构缩小到最容易理解的程度,那么编程开发其实只做3件事:”定义属性创建方法调用展示“。但因为同类所需的内容较多,如一系列的属性,一堆的方法实现,一组的接口封装,那么就需要合理的把这些内容分配到不同的层次中去实现,因此有了分层架构的设计。

那么本文小傅哥会向大家介绍一套MVC架构的分层设计以及如何创建使用,并提供相应的简单的案例。你可以复制这套架构在自己的场景中使用,也更能方便编程的小白可以更快的上手开发。

注意:此套MVC架构模型适合提供HTTP服务的工程架构,适合简单的小场景开发使用。特点;轻便、简单、学习成本低。

1. 编程三步

如果说你是一个特别小的玩具项目,你甚至可以把编程的3步写到一个类里。但因为你做的是正经项目,你的各种类;对象类、库表类、方法类,就会成群结队的来。如果你想把这些成群结队的类的内容,都写到一个类里去,那么就是几万行的代码了。—— 当然你也可以吹牛逼,你一个人做过一个项目,这项目大到啥程度呢。就是有一个类里有上万行代码。

所以,为了不至于让一个类撑到爆💥,需要把黄色的对象、绿色的方法、红色的接口,都分配到不同的包结构下。这就是你编码人生中所接触到的第一个解耦操作。

2. 分层框架

MVC 是一种非常常见且常用的分层架构,主要包括;M - mode 对象层,封装到 domain 里。V - view 展示层,但因为目前都是前后端分离的项目,几乎不会在后端项目里写 JSP 文件了。C - Controller 控制层,对外提供接口实现类。DAO 算是单独拿出来用户处理数据库操作的层。

  • 如图,在 MVC 的分层架构下。我们编程3步的所需各类对象、方法、接口,都分配到 MVC 的各个层次中去。
  • 因为这样分层以后,就可以很清晰明了的知道各个层都在做什么内容,也更加方便后续的维护和迭代。
  • 对于一个真正的项目来说,是没有一锤子买卖的,最开始的开发远不是成本所在。最大的开发成本是后期的维护和迭代。而架构设计的意义更多的就是在解决系统的反复的维护和迭代时,如何降低成本,这也是架构分层的意义所在。

3. 调用流程

接下来我们再看下一套 MVC 架构中各个模块在调用时的串联关系;

  • 以用户发起 HTTP 请求开始,Controller 在接收到请求后,调用由 Spring 注入到类里的 Service 方法,进入 Service 方法后有些逻辑会走数据库,有些逻辑是直接内部自己处理后就直接返回给 Controller 了。最后由 Controller 封装结果返回给 HTTP 响应。
  • 同时我们也可以看到各个对象在这些请求间的一个作用,如;请求对象、库表对象、返回对象。

4. 架构源码

4.1 环境

  • JDK 1.8
  • Maven 3.8.6 - 下载安装maven后,本地记得配置阿里云镜像,方便快速拉取jar包。源码中 docs/maven/settings.xml 有阿里云镜像地址。
  • SpringBoot 2.7.2
  • MySQL 5.7 - 如果你使用 8.0 记得更改 pom.xml 中的 mysql 引用

4.2 架构

  • 源码https://gitcode.net/KnowledgePlanet/road-map/xfg-frame-mvc
  • 树形安装 brew install tree IntelliJ IDEA Terminal 使用 tree
.
├── docs
│   └── mvc.drawio - 架构文档
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── cn
│   │   │       └── bugstack
│   │   │           └── xfg
│   │   │               └── frame
│   │   │                   ├── Application.java
│   │   │                   ├── common
│   │   │                   │   ├── Constants.java
│   │   │                   │   └── Result.java
│   │   │                   ├── controller
│   │   │                   │   └── UserController.java
│   │   │                   ├── dao
│   │   │                   │   └── IUserDao.java
│   │   │                   ├── domain
│   │   │                   │   ├── po
│   │   │                   │   │   └── User.java
│   │   │                   │   ├── req
│   │   │                   │   │   └── UserReq.java
│   │   │                   │   ├── res
│   │   │                   │   │   └── UserRes.java
│   │   │                   │   └── vo
│   │   │                   │       └── UserInfo.java
│   │   │                   └── service
│   │   │                       ├── IUserService.java
│   │   │                       └── impl
│   │   │                           └── UserServiceImpl.java
│   │   └── resources
│   │       ├── application.yml
│   │       └── mybatis
│   │           ├── config
│   │           │   └── mybatis-config.xml
│   │           └── mapper
│   │               └── User_Mapper.xml
│   └── test
│       └── java
│           └── cn
│               └── bugstack
│                   └── xfg
│                       └── frame
│                           └── test
│                               └── ApiTest.java
└── road-map.sql

以上是整个🏭工程架构的 tree 树形图。整个工程由 SpringBoot 驱动。

  • Application.java 是启动程序的 SpringBoot 应用
  • common 是额外添加的一个层,用于定义通用的类
  • controller 控制层,提供接口实现。
  • dao 数据库操作层
  • domain 对象定义层
  • service 服务实现层

5. 测试验证

  • 首先;整个工程由 SpringBoot 驱动,提供了 road-map.sql 测试 SQL 库表语句。你可以在自己的本地mysql上进行执行。它会创建库表。
  • 之后;在 application.yml 配置数据库链接信息。
  • 之后就可以打开 ApiTest 进行测试了。你可以点击 Application 类的绿色箭头启动工程,使用 UserController 类提供接口的方式调用程序;http://localhost:8089/queryUserInfo
- 如果你正常获取了这样的结果信息,那么说明你已经启动成功。接下来就可以对照着MVC的结构进行学习,以及使用这样的工程结构开发自己的项目。

二、DDD 架构

从最早接触 DDD 架构,到后来用 DDD 架构不断的承接项目开发,一次次在项目开发中的经验积累。对 DDD 有了不少的理解。DDD 是一种思想,落地的形态和结构会有不同的方式,甚至在编码上也会有风格的差异。但终期目标就一个;”提供代码的可维护性,降低迭代开发成本。“也是康威定律所述:”任何组织在设计一套系统时,所交付的设计方案在结构上都与该组织的沟通结构保持一致。“

但 DDD 与 MVC 相比的概率较多,贸然用理论驱动代码开发,会让整个工程变得非常混乱,甚至可能虽然是用的 DDD 但最后写出来了一片四不像的 MVC 代码。所以对于程序员👨🏻‍💻来说,先能上手一个工程,在从工程了解理论会更加容易。为此小傅哥想以此文,通过实战编码的方式向大家分享 DDD 架构,并能让大家上手的 DDD 架构。

1. 问题碰撞

你用 MVC 写代码,遇到过最大的问题是什么?🤔

简单、容易、好理解,是 MVC 架构的特点,但也正因为简单的分层逻辑,在适配较复杂的场景并且需要长周期的维护时,代码的迭代成本就会越来越高。如图;

  • 如果你接触过较大型且已经长期维护项目的 MVC 架构,你就会发现这里的 DAO、PO、VO 对象,在 Service 层相互调用。那么长期开发后,就导致了各个 PO 里的属性字段数量都被撑的特别大。这样的开发方式,将”状态”“行为“分离到不同的对象中,代码的意图渐渐模糊,膨胀、臃肿和不稳定的架构,让迭代成本增加。
  • 而 DDD 架构首先以解决此类问题为主,将各个属于自己领域范围内的行为和逻辑封装到自己的领域包下处理。这也是 DDD 架构设计的精髓之一。它希望在分治层面合理切割问题空间为更小规模的若干子问题,而问题越小就容易被理解和处理,做到高内聚低耦合。这也是康威定律所提到的,解决复杂场景的设计主要分为:分治、抽象和知识。

2. 简化理解

在给大家讲解 MVC 架构的时候,小傅哥提到了一个简单的开发模型。开发代码可以理解为:“定义属性 -> 创建方法 -> 调用展示” 但这个模型结构过于简单,不太适合运用了各类分布式技术栈以及更多逻辑的 DDD 架构。所以在 DDD 这里,我们把开发代码可以抽象为:“触发 -> 函数 -> 连接” 如图;

  • DDD 架构常用于微服务场景,因此也一个系统的调用方式就不只是 HTTP 还包括;RPC 远程MQ 消息TASK 任务,因此这些种方式都可以理解为触发。
  • 通过触发调用函数方法,我们这里可以把各个服务都当成一个函数方法来看。而函数方法通过连接,调用到其他的接口、数据库、缓存来完成函数逻辑。

接下来,小傅哥在带着大家把这些所需的模块,拆分到对应的DDD系统架构中。

3. 架构分层

如下是 DDD 架构的一种分层结构,也可以有其他种方式,核心的重点在于适合你所在场景的业务开发。以下的分层结构,是小傅哥在使用 DDD 架构多种的方式开发代码后,做了简化和处理的。右侧的连线是各个模块的依赖关系。接下来小傅哥就给大家做一下模块的介绍。

  • 接口定义 - xfg-frame-api:因为微服务中引用的 RPC 需要对外提供接口的描述信息,也就是调用方在使用的时候,需要引入 Jar 包,让调用方好能依赖接口的定义做代理。
  • 应用封装 - xfg-frame-app:这是应用启动和配置的一层,如一些 aop 切面或者 config 配置,以及打包镜像都是在这一层处理。你可以把它理解为专门为了启动服务而存在的。
  • 领域封装 - xfg-frame-domain:领域模型服务,是一个非常重要的模块。无论怎么做DDD的分层架构,domain 都是肯定存在的。在一层中会有一个个细分的领域服务,在每个服务包中会有【模型、仓库、服务】这样3部分。
  • 仓储服务 - xfg-frame-infrastructure:基础层依赖于 domain 领域层,因为在 domain 层定义了仓储接口需要在基础层实现。这是依赖倒置的一种设计方式。
  • 领域封装 - xfg-frame-trigger:触发器层,一般也被叫做 adapter 适配器层。用于提供接口实现、消息接收、任务执行等。所以对于这样的操作,小傅哥把它叫做触发器层。
  • 类型定义 - xfg-frame-types:通用类型定义层,在我们的系统开发中,会有很多类型的定义,包括;基本的 Response、Constants 和枚举。它会被其他的层进行引用使用。
  • 领域编排【可选】 - xfg-frame-case:领域编排层,一般对于较大且复杂的的项目,为了更好的防腐和提供通用的服务,一般会添加 case/application 层,用于对 domain 领域的逻辑进行封装组合处理。

4. 架构源码

4.1 环境

  • JDK 1.8
  • Maven 3.8.6
  • SpringBoot 2.7.2
  • MySQL 5.7 - 如果你使用 8.0 记得更改 pom.xml 中的 mysql 引用

4.2 架构

  • 源码https://gitcode.net/KnowledgePlanet/road-map/xfg-frame-ddd
  • 树形安装 brew install tree IntelliJ IDEA Terminal 使用 tree
.
├── README.md
├── docs
│   ├── dev-ops
│   │   ├── environment
│   │   │   └── environment-docker-compose.yml
│   │   ├── siege.sh
│   │   └── skywalking
│   │       └── skywalking-docker-compose.yml
│   ├── doc.md
│   ├── sql
│   │   └── road-map.sql
│   └── xfg-frame-ddd.drawio
├── pom.xml
├── xfg-frame-api
│   ├── pom.xml
│   ├── src
│   │   └── main
│   │       └── java
│   │           └── cn
│   │               └── bugstack
│   │                   └── xfg
│   │                       └── frame
│   │                           └── api
│   │                               ├── IAccountService.java
│   │                               ├── IRuleService.java
│   │                               ├── model
│   │                               │   ├── request
│   │                               │   │   └── DecisionMatterRequest.java
│   │                               │   └── response
│   │                               │       └── DecisionMatterResponse.java
│   │                               └── package-info.java
│   └── xfg-frame-api.iml
├── xfg-frame-app
│   ├── Dockerfile
│   ├── build.sh
│   ├── pom.xml
│   ├── src
│   │   ├── main
│   │   │   ├── bin
│   │   │   │   ├── start.sh
│   │   │   │   └── stop.sh
│   │   │   ├── java
│   │   │   │   └── cn
│   │   │   │       └── bugstack
│   │   │   │           └── xfg
│   │   │   │               └── frame
│   │   │   │                   ├── Application.java
│   │   │   │                   ├── aop
│   │   │   │                   │   ├── RateLimiterAop.java
│   │   │   │                   │   └── package-info.java
│   │   │   │                   └── config
│   │   │   │                       ├── RateLimiterAopConfig.java
│   │   │   │                       ├── RateLimiterAopConfigProperties.java
│   │   │   │                       ├── ThreadPoolConfig.java
│   │   │   │                       ├── ThreadPoolConfigProperties.java
│   │   │   │                       └── package-info.java
│   │   │   └── resources
│   │   │       ├── application-dev.yml
│   │   │       ├── application-prod.yml
│   │   │       ├── application-test.yml
│   │   │       ├── application.yml
│   │   │       ├── logback-spring.xml
│   │   │       └── mybatis
│   │   │           ├── config
│   │   │           │   └── mybatis-config.xml
│   │   │           └── mapper
│   │   │               ├── RuleTreeNodeLine_Mapper.xml
│   │   │               ├── RuleTreeNode_Mapper.xml
│   │   │               └── RuleTree_Mapper.xml
│   │   └── test
│   │       └── java
│   │           └── cn
│   │               └── bugstack
│   │                   └── xfg
│   │                       └── frame
│   │                           └── test
│   │                               └── ApiTest.java
│   └── xfg-frame-app.iml
├── xfg-frame-ddd.iml
├── xfg-frame-domain
│   ├── pom.xml
│   ├── src
│   │   └── main
│   │       └── java
│   │           └── cn
│   │               └── bugstack
│   │                   └── xfg
│   │                       └── frame
│   │                           └── domain
│   │                               ├── order
│   │                               │   ├── model
│   │                               │   │   ├── aggregates
│   │                               │   │   │   └── OrderAggregate.java
│   │                               │   │   ├── entity
│   │                               │   │   │   ├── OrderItemEntity.java
│   │                               │   │   │   └── ProductEntity.java
│   │                               │   │   ├── package-info.java
│   │                               │   │   └── valobj
│   │                               │   │       ├── OrderIdVO.java
│   │                               │   │       ├── ProductDescriptionVO.java
│   │                               │   │       └── ProductNameVO.java
│   │                               │   ├── repository
│   │                               │   │   ├── IOrderRepository.java
│   │                               │   │   └── package-info.java
│   │                               │   └── service
│   │                               │       ├── OrderService.java
│   │                               │       └── package-info.java
│   │                               ├── rule
│   │                               │   ├── model
│   │                               │   │   ├── aggregates
│   │                               │   │   │   └── TreeRuleAggregate.java
│   │                               │   │   ├── entity
│   │                               │   │   │   ├── DecisionMatterEntity.java
│   │                               │   │   │   └── EngineResultEntity.java
│   │                               │   │   ├── package-info.java
│   │                               │   │   └── valobj
│   │                               │   │       ├── TreeNodeLineVO.java
│   │                               │   │       ├── TreeNodeVO.java
│   │                               │   │       └── TreeRootVO.java
│   │                               │   ├── repository
│   │                               │   │   ├── IRuleRepository.java
│   │                               │   │   └── package-info.java
│   │                               │   └── service
│   │                               │       ├── engine
│   │                               │       │   ├── EngineBase.java
│   │                               │       │   ├── EngineConfig.java
│   │                               │       │   ├── EngineFilter.java
│   │                               │       │   └── impl
│   │                               │       │       └── RuleEngineHandle.java
│   │                               │       ├── logic
│   │                               │       │   ├── BaseLogic.java
│   │                               │       │   ├── LogicFilter.java
│   │                               │       │   └── impl
│   │                               │       │       ├── UserAgeFilter.java
│   │                               │       │       └── UserGenderFilter.java
│   │                               │       └── package-info.java
│   │                               └── user
│   │                                   ├── model
│   │                                   │   └── valobj
│   │                                   │       └── UserVO.java
│   │                                   ├── repository
│   │                                   │   └── IUserRepository.java
│   │                                   └── service
│   │                                       ├── UserService.java
│   │                                       └── impl
│   │                                           └── UserServiceImpl.java
│   └── xfg-frame-domain.iml
├── xfg-frame-infrastructure
│   ├── pom.xml
│   ├── src
│   │   └── main
│   │       └── java
│   │           └── cn
│   │               └── bugstack
│   │                   └── xfg
│   │                       └── frame
│   │                           └── infrastructure
│   │                               ├── dao
│   │                               │   ├── IUserDao.java
│   │                               │   ├── RuleTreeDao.java
│   │                               │   ├── RuleTreeNodeDao.java
│   │                               │   └── RuleTreeNodeLineDao.java
│   │                               ├── package-info.java
│   │                               ├── po
│   │                               │   ├── RuleTreeNodeLineVO.java
│   │                               │   ├── RuleTreeNodeVO.java
│   │                               │   ├── RuleTreeVO.java
│   │                               │   └── UserPO.java
│   │                               └── repository
│   │                                   ├── RuleRepository.java
│   │                                   └── UserRepository.java
│   └── xfg-frame-infrastructure.iml
├── xfg-frame-trigger
│   ├── pom.xml
│   ├── src
│   │   └── main
│   │       └── java
│   │           └── cn
│   │               └── bugstack
│   │                   └── xfg
│   │                       └── frame
│   │                           └── trigger
│   │                               ├── http
│   │                               │   ├── Controller.java
│   │                               │   └── package-info.java
│   │                               ├── mq
│   │                               │   └── package-info.java
│   │                               ├── rpc
│   │                               │   ├── AccountService.java
│   │                               │   ├── RuleService.java
│   │                               │   └── package-info.java
│   │                               └── task
│   │                                   └── package-info.java
│   └── xfg-frame-trigger.iml
└── xfg-frame-types
    ├── pom.xml
    ├── src
    │   └── main
    │       └── java
    │           └── cn
    │               └── bugstack
    │                   └── xfg
    │                       └── frame
    │                           └── types
    │                               ├── Constants.java
    │                               ├── Response.java
    │                               └── package-info.java
    └── xfg-frame-types.iml

以上是整个🏭工程架构的 tree 树形图。整个工程由 xfg-frame-app 模的 SpringBoot 驱动。这里小傅哥在 domain 领域模型下提供了 order、rule、user 三个领域模块。并在每个模块下提供了对应的测试内容。这块是整个模型的重点,其他模块都可以通过测试看到这里的调用过程。

4.3 领域

一个领域模型中包含3个部分;model、repository、service 三部分;

  • model 对象的定义
  • repository 仓储的定义
  • service 服务实现

以上3个模块,一般也是大家在使用 DDD 时候最不容易理解的分层。比如 model 里还分为;valobj - 值对象、entity 实体对象、aggregates 聚合对象;

  • 值对象:表示没有唯一标识的业务实体,例如商品的名称、描述、价格等。
  • 实体对象:表示具有唯一标识的业务实体,例如订单、商品、用户等;
  • 聚合对象:是一组相关的实体对象的根,用于保证实体对象之间的一致性和完整性;

关于model中各个对象的拆分,尤其是聚合的定义,会牵引着整个模型的设计。当然你可以在初期使用 DDD 的时候不用过分在意领域模型的设计,可以把整个 domain 下的一个个包当做充血模型结构,这样编写出来的代码也是非常适合维护的。

4.4 环境(开发/测试/上线)

源码xfg-frame-ddd/pom.xml

<profile>
    <id>dev</id>
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>
    <properties>
        <profileActive>dev</profileActive>
    </properties>
</profile>
<profile>
    <id>test</id>
    <properties>
        <profileActive>test</profileActive>
    </properties>
</profile>
<profile>
    <id>prod</id>
    <properties>
        <profileActive>prod</profileActive>
    </properties>
</profile>
  • 定义环境;开发、测试、上线。

源码xfg-frame-app/application.yml

spring:
  config:
    name: xfg-frame
  profiles:
    active: dev # dev、test、prod
  • 除了 pom 的配置,还需要在 application.yml 中指定环境。这样就可以对应的加载到;application-dev.ymlapplication-prod.ymlapplication-test.yml 这样就可以很方便的加载对应的配置信息了。尤其是各个场景中切换会更加方便。

4.5 切面

一个工程开发中,有时候可能会有很多的统一切面和启动配置的处理,这些内容都可以在 xfg-frame-app 完成。

源码cn.bugstack.xfg.frame.aop.RateLimiterAop

@Slf4j
@Aspect
public class RateLimiterAop {

    private final long timeout;
    private final double permitsPerSecond;
    private final RateLimiter limiter;

    public RateLimiterAop(double permitsPerSecond, long timeout) {
        this.permitsPerSecond = permitsPerSecond;
        this.timeout = timeout;
        this.limiter = RateLimiter.create(permitsPerSecond);
    }

    @Pointcut("execution(* cn.bugstack.xfg.frame.trigger..*.*(..))")
    public void pointCut() {
    }

    @Around(value = "pointCut()", argNames = "jp")
    public Object around(ProceedingJoinPoint jp) throws Throwable {
        boolean tryAcquire = limiter.tryAcquire(timeout, TimeUnit.MILLISECONDS);
        if (!tryAcquire) {
            Method method = getMethod(jp);
            log.warn("方法 {}.{} 请求已被限流,超过限流配置[{}/秒]", method.getDeclaringClass().getCanonicalName(), method.getName(), permitsPerSecond);
            return Response.<Object>builder()
                    .code(Constants.ResponseCode.RATE_LIMITER.getCode())
                    .info(Constants.ResponseCode.RATE_LIMITER.getInfo())
                    .build();
        }
        return jp.proceed();
    }

    private Method getMethod(JoinPoint jp) throws NoSuchMethodException {
        Signature sig = jp.getSignature();
        MethodSignature methodSignature = (MethodSignature) sig;
        return jp.getTarget().getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
    }

}

使用

# 限流配置
rate-limiter:
  permits-per-second: 1
  timeout: 5
  • 这样你所有的通用配置,又和业务没有太大的关系的,就可以直接写到这里了。—— 具体可以参考代码。

5. 测试验证

  • 首先;整个工程由 SpringBoot 驱动,提供了 road-map.sql 测试 SQL 库表语句。你可以在自己的本地mysql上进行执行。它会创建库表。
  • 之后;在 application.yml 配置数据库链接信息。
  • 之后就可以打开 ApiTest 进行测试了。你可以点击 Application 类的绿色箭头启动工程,使用触发器里的接口调用测试,或者单元测试RPC接口,小傅哥也提供了泛化调用的方式。
  • 如果你正常获取了这样的结果信息,那么说明你已经启动成功。接下来就可以对照着DDD的结构进行学习,以及使用这样的工程结构开发自己的项目。

三、实战 - DDD 项目

纸上得来终觉浅,码农学习要实战!

无论是 MVC 还是各类 DDD 所呈现的架构,还是需要看到实际的代码,以及参与实战开发才能更好的吸收。否则都是理论仍旧难以让人下手。

所以小傅哥为大家准备了一些学习项目,这些项目都是非常具有架构思维以及设计模式的应用级实战项目架构设计和落地。对于一些小白来说,如果能早早的接触到这样的项目,就相当于是提前进入企业实习了。可以极大的提到编程思维以及开发能力。

这些项目包括:《Lottery 抽奖系统 - 基于领域驱动设计的四层架构实践》、《API网关:中间件设计和落地》、《ChatGPT 微服务应用体系搭建》、《IM 仿微信》、《SpringBoot Starter 中间件设计和落地》等。这里小傅哥只列3张图,你就知道有多牛皮了!

第1张:Lottery

架构

工程

第2张:API网关

架构

工程

第3张:ChatGPT


实战项目:https://bugstack.cn/md/zsxq/introduce.html

此外,小傅哥还给大家准备了一系列的《Java简明教程》视频,进入B站即可学习!

https://www.bilibili.com/video/BV1kV411g7GX

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/715315.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UE4/5用GeneratedDynamicMeshActor创建多个模型,并发生Boolean(两个网格体之间的,有3种模式)

目录 制作 只创建一个球&#xff1a; 效果&#xff1a; 制作多个效果&#xff1a; 制作&#xff1a; 效果&#xff1a; 代码&#xff1a; 一代码&#xff1a; 二代码&#xff1a; 制作 假如我们创建两个模型&#xff0c;第一个是之前就创建的正方体&#xff0c;而第二…

PHP:查询数据库,并将数据传给前端(在script中直接嵌套php语句)

例子&#xff1a;在php中定义数据&#xff0c; 并将数据通过js在控制台输出 <script><?php// 在这里插入你的PHP代码&#xff0c;例如执行查询操作获取数据$data array(array(name > Alice, age > 25),array(name > Bob, age > 30),array(name > Ch…

(7)深度学习学习笔记-卷积层

文章目录 前言一、实现二维互相关和卷积层二、用nn的Conv2d给定输入X和输出Y&#xff0c;生成核K1.引入库2.简单实现 来源 前言 在卷积层中&#xff0c;输入张量和核张量通过互相关运算产生输出张量。 阴影部分是第一个输出元素&#xff0c;以及用于计算输出的输入张量元素和…

【直播预告】HarmonyOS极客松赋能直播第四期:HarmonyOS开发经验分享

直播预约通道&#xff1a;【直播预告】HarmonyOS极客松赋能直播第四期&#xff1a;HarmonyOS开发经验分享

【数据库】使用DBever连接人大金仓数据库

下载安装DBever 首先需要下载并安装DBever&#xff0c;可以在DBever官网上下载最新版的安装程序&#xff0c;根据提示进行安装即可。 下载驱动程序 首先需要从人大金仓官方网站下载适用于DBever的驱动程序。下载完成后&#xff0c;将驱动程序保存到本地计算机上。 添加驱动…

docker deploy rancher

docker run --privileged -d --name rancher --restartunless-stopped -p 80:80 -p 443:443 rancher/rancher:latest docker ps docker logs 4d890c673011 2>&1 | grep “Bootstrap Password:”

LCD屏幕显示文字(含交叉编译freetype字体矢量库)

文章目录 字符的编码方式编码与字体ASCIIANSIUNICODEUNICODE 编码实现 ASCII 字符的点阵显示ASCII字符文件主要代码 中文字符的点阵显示指定编码格式汉字的点阵数据&#xff08;汉字区位码&#xff09; 交叉编译 freetype 矢量库程序运行的一些基础知识怎么确定“系统目录”&am…

【08】STM32·HAL库开发-HAL库介绍 | STM32Cube固件库介绍 | HAL库框架结构 | 如何使用HAL库及使用注意事项

目录 1.初识HAL库&#xff08;了解&#xff09;1.1CMSIS简介1.2HAL库简介 2.STM32Cube固件包浅析&#xff08;了解&#xff09;2.1如何获取STM32Cube固件包&#xff1f;2.2STM32Cube固件包文件夹简介2.3CMSIS文件夹关键文件2.3.1CMSIS标准规定软件包目录2.3.2Device和Include文…

背光图像增强论文调研

背光图像增强 M. Akai, Y. Ueda, T. Koga and N. Suetake, “A Single Backlit Image Enhancement Method For Improvement Of Visibility Of Dark Part,” 2021 IEEE International Conference on Image Processing (ICIP), Anchorage, AK, USA, 2021, pp. 1659-1663, doi: 10…

山西电力市场日前价格预测【2023-07-05】

日前价格预测 预测明日&#xff08;2023-07-05&#xff09;山西电力市场全天平均日前电价为168.88元/MWh。其中&#xff0c;最高日前电价为334.22元/MWh&#xff0c;预计出现在20: 30。最低日前电价为0.00元/MWh&#xff0c;预计出现在09: 45-17: 15。 以上预测仅供学习参考&a…

【Git】中文显示数字的问题的解决方案

目录 问题截图解决方案 问题截图 运行git status命令&#xff0c;会出现图片中不正常显示中文的问题 解决方案 设置终端: 右键窗口头部 -> Options...执行命令: git config --global core.quotepath false

电脑屏幕监控软件是什么?有哪些功能?

电脑屏幕监控软件是一种用于监视和记录电脑屏幕活动的工具。它可以捕捉屏幕上的所有操作&#xff0c;包括键盘输入、鼠标点击、应用程序使用等。这些软件通常被用于家庭、教育机构和企业等环境中&#xff0c;以确保电脑的安全和监督员工或孩子的活动。 为什么需要电脑屏幕监控软…

STM32实战项目—密码锁

该项目的完整工程可以在博主的资源里找到&#xff0c;仅供参考。 文章目录 一、任务要求二、实现方法2.1 输入密码判断2.2 管理员模式2.3 修改密码 三、程序设计3.1 输入密码判断3.2 进入管理员模式3.3 修改密码 四、问题总结4.1 输入内容一直提示Error4.2 密码判断一直错误 五…

Lua,不使用模块,解压文件

本来lua遍历文件夹下压缩包内容、路径可以通过加载模块&#xff1a; require(“lfs”) 和 require(“zip”) 来解决。 但是本人通过c调用lua时&#xff0c;只要lua脚本中使用require加载模块&#xff0c;就会出错。 因此为了能够让c通过lua&#xff0c;解压当前路径下压缩包&a…

【基础算法】回溯算法相关题目

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招算法的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于代码随想录进行的&#xff0c;每个算法代码参考leetcode高赞回答和…

Android RecyclerView AsyncListUtil手动刷新fillData,kotlin

Android RecyclerView AsyncListUtil手动刷新fillData&#xff0c;kotlin implementation com.github.bumptech.glide:glide:4.15.1implementation androidx.constraintlayout:constraintlayout:1.1.3 import android.os.Bundle import android.util.Log import android.view.V…

百万连接实现02:使用epoll实现的服务器

使用的操作系统&#xff1a; t$ cat /proc/version Linux version 4.19.260 (lkmaoubuntu) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.12)) #1 SMP Thu Sep 29 14:19:07 CST 2022 文件句柄的限制 如果不修改连接测试&#xff0c;会报错 一个tcp连接就需要…

北京大学2015计算机学科夏令营上机考试

目录 A:整数的个数 B:过滤多余的空格 C:二维数组右上左下遍历 D 合影效果 E:Simple prefix compression【做不起】 F:To Europe! To Europe!【做不起】 G:The Game【做不起】 H:Falling Leaves A:整数的个数 #include<iostream> using namespace std; int main(…

VSCode 免安装及中文设置

前言&#xff1a;VSCode作为目前最强大的文本编辑器&#xff0c;通过内部的插件市场可满足各种开发需求。使用免安装版可以自定义插件安装位置等&#xff0c;而使用安装包安装只能通过修改快捷方式自定义&#xff0c;十分不方便。因此这里分享如何安装免安装版的VSCode。 下载…

ETL是什么?怎样更快的学习ETL?

ETL是英文Extract-Transform-Load的缩写&#xff0c;用来描述将数据从源端经过抽取(extract)、转换(transform)、加载(load)至目的端的过程&#xff0c;它能够对各种分布的、异构的源数据(如关系数据)进行抽取&#xff0c;按照预先设计的规则将不完整数据、重复数据以及错误数据…