什么是DDD?万字长文案例带你由浅入深领域驱动设计领域驱动设计(DDD)是一种软件架构思想,强调以业务为核心,提升软件的

在我们习惯了J2EE的开发模式后,Action/Service/DAO这种分层模式,会很自然地写出过程式代码,而学到的很多关于OO理论的也毫无用武之地。使用这种开发方式,对象只是数据的载体,没有行为。以数据为中心,以数据库ER设计作驱动。分层架构在这种开发模式下,可以理解为是对数据移动、处理和实现的过程。

我更愿意称DDD是一种架构思想,而不是一种“框架”,框架给人一种死板的感觉。事实也是这样,自然世界是复杂多变的,业务随着需求的变化也在不断的改变,仅采用固定的一套框架,告诉你,我们用DDD框架,什么代码应该放在哪个包,这并不是DDD的目的。我们来谈谈目前大家应该都了解的MVC架构。MVC分层架构是非常优秀的一种架构体系,ORM框架的盛行更是助燃了MVC的发展。在Mybatis的帮助下,我们的代码结构不可避免会有如下几个包,controller,service,mapper,pojo。借用工具,我们的pojo层的实现变得死板简单,仅仅只是与数据库表对应,面向对象编程的思想逐渐转化为面向数据库表编程。在十年前,大部分的商业应用还处于单机时代,分布式微服务的概念还未盛行。大家的API调用大多都是基于REST接口的外部调用。

在之后,服务概念开始冒头,从一开始的SOA架构,到后面更加细致的微服务架构,甚至于如今盛行的所谓“云原生”,“serverless架构”。微服务崇尚的是业务的拆分,拆分为高内聚低耦合的服务,而DDD也是同样着重于业务的视角,两者在追求同样的目标达到了上下文统一。微服务场景下,服务调用方式不仅是REST,RPC以及消息队列的调用方式变得更加常见,服务之间的依赖关系变得错综复杂,如何去合理拆分服务也成为了一大挑战和难题。一个电商系统拆分,难道全部笼统的拆分于用户模块,商家模块,商品模块,店铺模块......DDD的思想是领域驱动设计,DomainDrivenDesign,这种思想让我们能真正冷静下来,去思考到底哪些东西可以被服务化拆分,哪些逻辑需要聚合,才能带来最小的维护成本,而不是简单的去追求开发效率。GordonMoore提出软件设计好坏的标准是,高内聚低耦合,无论是单机时代,再到分布式时代,乃至今天的微服务云原生时代,这一言论依然可行,那么什么是高内聚与低耦合,DDD思想如何帮助我们设计出一个优秀的软件架构呢?

DP是DDD架构中的核心角色,也可以理解为最小单位,他明显区别于MVC架构中的model,最简单理解就是,充血模型与贫血模型。DomainPrimitive是一个在特定领域里,拥有精准定义的、可自我验证的、拥有行为的ValueObject。下面我用一个订单的简单例子介绍一下什么是贫血模型,什么又是充血模型。

贫血模型是一种将业务逻辑与数据分离的设计方式。在这种模型中,领域对象通常只包含数据属性,而业务逻辑则分布在服务类(Service)中。领域对象在这种设计中更像是数据的载体,而实际的操作和逻辑处理则由独立的服务类负责。以下代码中,Order类仅包含订单的属性,这些属性一般和我们的数据库表对应,而所有的逻辑均放在我们的Service服务层进行处理。这种模型较为简单,并且比较清晰,但是他不符合高内聚的特点,是一种低内聚的设计,可惜的是,目前市面上绝大多数的教学,以及初学者都是应用这种模型进行编码。

一个招商系统需要在全国范围内进行招商,商家需要注册进这个招商系统,根据商家经营的商品种类,对商家的type进行区分,并且根据商家负责人的手机号,划定这个商家的地域。

我们先不要管这个业务合理不合理,我们着手于实践,这个需求拿到我们手上,我们用MVC的方式去拆分那便是一个Merchant(商家类),包含了商家的基本属性,一个Respository用来于持久层交互,然后在服务层拼凑实现我们的业务。代码如下:

数据模型(pojo)

publicclassMerchant{privateLongid;privateStringname;privateStringphone;privateStringproductCategory;privateStringtype;privateStringregion;//gettersandsetters}数据访问层(dao)

但是,以上给出的例子,还不是很“纯血”的DP。

跟着我的思路,我们现在来看这个注册商家的需求,假设需要以下一个接口

注册(商家名称,手机号),那么自然的我们会想到这样设计接口

publicvoidregister(Stringname,StringphoneNumber);在Java代码中,对于一个方法来说,所有的参数名在编译后消失,那么我们的代码在编译后其实是这样的

publicvoidregister(String,String)那么假设我们在service层这样调用接口,是否会出错呢?

merchant.register("17720778576","AAA潮鞋直营店");答案是不会的,虽然接口定义是name和phoneNumber,但是这两个参数都是String,我们传递手机号和商铺名字进去,自然是正确的,为什么会报错呢?或许现在还有些读者会看不明白,这样写有什么问题。问题就是我们定义的接口是先传入name再传入phoneNumber。而样例中我先传入了phoneNumber。

问题是这样在我们的代码编译过程中是不会出问题的,这个bug就会留到测试中显示出为业务问题,一段良好的代码应该具有更少的测试风险,测试诚然是必不可少的工作,但是倘若代码本身就具有自我检查机制,那么测试的工作量是否会减少,并且对于排查错误以及代码健壮性来说,都有极佳的意义。

那么我们要怎样改进这个方法。

首先就是把隐形的概念显性化,我们把phoneNumber和name中隐藏的业务逻辑显性化。创建PhoneNumber类和Name类。

publicclassMerchant{privateNamename;privatePhoneNumberphoneNumber;privateStringtype;privateStringregion;publicMerchant(Namename,PhoneNumberphoneNumber){this.name=name;this.phoneNumber=phoneNumber;this.type=determineType();this.region=determineRegion();}privateStringdetermineType(){//假设我们可以通过名字或其他方式来确定类型if(name.getName().contains("潮鞋")){return"鞋类";}else{return"其他";}}privateStringdetermineRegion(){returnphoneNumber.getAreaCode();}publicNamegetName(){returnname;}publicPhoneNumbergetPhoneNumber(){returnphoneNumber;}publicStringgetType(){returntype;}publicStringgetRegion(){returnregion;}}那么我们在真正调用这个register函数的时候,就需要改成如下调用。

register(newName("AAA潮鞋专卖"),newPhoneNumber("17720778576"));这样即便我们是跨层调用,业务属性也非常明显的显示出来,也再也不会出现,参数传递顺序错误的问题。假设出现

register(newPhoneNumber("17720778576"),newName("AAA潮鞋专卖"));那么编译器就会报错,无该函数的定义。这就把测试的工作提前到开发阶段完成,提高了代码的健壮性。

那么到这里,到底什么是DP,直白的说,就是这边我们创建的PhoneNumber和Name类,而这个Merchant便是由DP组成的domainservice。也就是领域层模型

何为架构,这边引用一位阿里技术大佬的描述

架构这个词源于英文里的“Architecture“,源头是土木工程里的“建筑”和“结构”,而架构里的”架“同时又包含了”架子“(scaffolding)的含义,意指能快速搭建起来的固定结构。而今天的应用架构,意指软件系统中固定不变的代码结构、设计模式、规范和组件间的通信方式。在应用开发中架构之所以是最重要的第一步,因为一个好的架构能让系统安全、稳定、快速迭代。在一个团队内通过规定一个固定的架构设计,可以让团队内能力参差不齐的同学们都能有一个统一的开发规范,降低沟通成本,提升效率和代码质量。

在做架构设计时,一个好的架构应该需要实现以下几个目标:

了解了DP和充血模型的概念,那么一个DDD的应用架构如何落地,又或者说。我们为什么需要DDD架构思想,一个MVC系统如何向DDD架构转变呢?

我们继续引出一个具体的业务例子,非常简单,那就是实现一个跨币种的转账功能。

这个转账功能涉及到的业务点就是实现转入转出业务,并且涉及到跨币种还需要实时的去查看汇率,并且给出相应计算。这么简单的业务经过初步的技术选型后,可能会拆解成以下需求步骤

1、从MySql数据库中找到转出和转入的账户,选择用MyBatis的mapper实现DAO;

2、从一个RPC服务提供的汇率服务获取转账的汇率信息,假设是google提供

3、计算需要转出的金额,确保账户有足够余额。

4、实现转入和转出操作,扣除手续费,保存数据库;

5、发送Kafka审计消息,以便审计和对账用;

代码实现如下

一个应用最大的成本一般都不是来自于开发阶段,而是应用整个生命周期的总维护成本,所以代码的可维护性代表了最终成本。

可维护性=当依赖变化时,有多少代码需要随之改变。

首先我们依赖于Account类,它是纯映射于数据库表的,数据库字段的变更是及其常见的,因此这个类要跟着数据库字段的改变而改变,他是及其不稳定的。并且我们显示的依赖了kafka,外部rpc服务,mybatis等。倘若有一天jar包依赖升级,或者我们不使用kafka改为rocketmq,又或者mybatis出现重大漏洞,需要迁移ORM层?那便是灾难性的代码重构体验,但是这些组件本是为业务服务的,而如今业务没有变化,只是因为组件本身的问题,我们便要对业务层代码做这么深的重构,这就涉及到一个问题。

代码的腐败,特别是一个大型项目中,对于外部组件高度耦合的代码变得难以维护,假设我们发现Mybatis出了一个新的版本,性能提升百分之五十,但是调用方式API有了很大的变化,采用这种架构的代码由于代码耦合,想要更换新版本需要耗费的精力和危险性大大增加,于是即使我们深刻的明白,更换新版本是可以直接提升系统性能,但是碍于种种,只能推迟这个计划。

我们的业务逻辑这么长,但是却只能使用在register这个方法中,业务无法复用,且业务逻辑和数据库格式高度耦合,有新的需求进来,我们又只能新建一个方法,再次用脚本描述的方法来完成这新的一题“模拟题”,久而久之,代码变得不可维护,代码量和架构也变得混乱模糊不清。

参考以上的一段代码,这种代码有极低的可测试性:

我们回到软件工程最基本的设计三大理念

可以看到,一个转账的简单例子,看似合理的设计,却违背了软件工程设计的三大原则。

我们需要对代码重构才能解决这些问题。在这之前,我们先画出以上有问题的代码的依赖图

我们发现在业务层对下层基建层有很明显的强依赖,耦合度很高,所以需要对上图节点做抽象处理,来降低对外部依赖的耦合度。

这一层的操作其实是比较简单的,首先我们来看到第一个问题,我们Service中操作的对象与数据库强关联,且这个对象本身只是对数据库的简单映射,自身不带有业务属性。那么要解决这个问题,很自然就联想到我们上文提到的DP和DomainService的概念。首先我们应该保留和数据库直接映射的类,命名为AccoutDo,Do类与数据库直接映射,同时我们又需要有DomainService类,也就是我们在Service层中直接使用的Accout类,这个Accout和数据库有一定关系,但是他并不是直接依赖于数据库的,他不但有数据库字段的属性,他还能有自身的业务行为。简单代码示范如下。

@DatapublicclassAccount{//可以看到,这边的属性我们使用了DP做处理,这样也顺便解决了参数校验的问题privateAccountIdid;privateAccountNumberaccountNumber;privateUserIduserId;privateMoneyavailable;privateMoneydailyLimit;//这里带有了这个domain自身的一些高内聚的方法函数publicvoidwithdraw(Moneymoney){//转出}publicvoiddeposit(Moneymoney){//转入}}@DatapublicclassAccountDo{//直接与数据库一一映射privateLongid;privateStringaccountNumber;privateLonguserId;privateDoubleavailable;privateDoubledailyLimit;}在这边我们还需要一个DAO,这个DAO很好理解,就是对应数据库类型的一个真实操作,比如Mysql的insert,update,然后我们还需要一个Repository。

这时候这个Repository需要做两件事

代码样例

经过这样的架构转变,我们看到计算更新等业务操作也是直接依赖于Accout这个领域对象,然后领域对象依赖于Repository做映射,最下层才依赖具体的Mapper实现,就解决了业务层依赖于具体实现的问题。当我们需要更换数据库或者ORM的时候,Service层代码完全不需要改变,只需要去改变相应的Mapper层实现即可。这便是单一职责原则。

在这里我想先引出一个概念。Anti-CorruptionLayer(防腐层或ACL)。

很多时候我们的系统会去依赖其他的系统,而被依赖的系统可能包含不合理的数据结构、API、协议或技术实现,如果对外部系统强依赖,会导致我们的系统被”腐蚀“。这个时候,通过在系统间加入一个防腐层,能够有效的隔离外部依赖和内部逻辑,无论外部如何变更,内部代码可以尽可能的保持不变。

目的就是让我们的Service依赖于抽象而不是依赖于具体实现,真正的转换是通过反腐层去做的,而我们调用的永远是一个固定的抽象的业务接口,具体的适配器转换模式,下沉到防腐层中去实现。

我们这里有一个第三方的服务,googleExchangeRateService,他是依赖于google的。我们假设google服务返回的是这个json

{"source":"USD","rates":{"EUR":0.8534,"JPY":110.32,"GBP":0.7542,"CNY":6.4567},"timestamp":1625123456}但是将来某一天google服务不可用,或者收费变贵了,我们想改用雅虎服务,返回的json格式是这样的

{"base":"USD","date":"2024-07-01","rates":{"EUR":0.8456,"JPY":111.20,"GBP":0.7498,"CNY":6.5102}}因为我们在Service层强依赖google服务,所以需要对业务代码再次进行修改。

引入ACL层后,我们可以抽象出一个统一的json格式

{"source":"USD","date":"2024-07-01","rates":{"EUR":{"rate":0.8534,},"JPY":{"rate":110.32,},"GBP":{"rate":0.7542,},"CNY":{"rate":6.4567,}}}做一个适配器模式的转换,无论我们从什么数据源获取到汇率数据,我们都使用这个ACL层的适配器转换为我们需要的数据格式,所以在我们的Service业务层就可以依赖于抽象,也就是ExchangeRateService,无论这个Service底层依赖于哪个第三方的服务,返回的数据格式经过防腐层都是永远固定不变的。

同样的对于MQ,我们也可以抽象中间件,无论是RocketMQ,kafka,我们都可以抽象为MessageQueue。并且使用ACL层做一次适配。适配多种MQ实现,这样我们的业务层只依赖于抽象的mq,而不是依赖于具体的mq实现。

这一步就是把部分业务逻辑再内聚到我们的domain里面,比如汇率计算。

最后我们业务层代码就可以只写成

DoubleamountInFromCurrency=getFromCurrency(amount);结果展示经过以上种种重构,最后我们的业务代码会变得无比干净

可以看出来,经过重构后的代码有以下几个特征:

那么真正落地一个DDD项目,我们该如何分模块分包呢。由于业务的复杂性,以及每个公司落地DDD风格的不同,我不能给出一个绝对的答案,以下仅仅是抛砖引玉,给出一个比较基础简单的分包。

类比于Integer,String,Double这些type,我们的DP也是一个个包含业务校验逻辑的Type,因此Types模块中我们存放DP

Domain模块是核心业务逻辑的集中地,包含有状态的Entity、领域服务DomainService、以及各种外部依赖的接口类(如Repository、ACL、中间件等。Domain模块仅依赖Types模块,也是纯POJO。

这个模块主要依赖于Domain模块,他就是我们MVC结构中的service模块,用于组装拓展Domain中的业务逻辑,形成真正具体的业务需求函数

基建模块,依赖于具体的基建实现,包括DB,MQ,ORM层的依赖。

DDD架构不是一个具体的特殊的架构模式,他的理念是所有传统代码经过合理的重构要达到的终点,在当下爆炸的微服务时代,业务呈井喷发展,我们推崇敏捷开发的同时,更要注重代码的健壮性,以及可维护性。DDD架构能够有效的解决传统架构中的问题。

在一个电商系统中订单管理是一个领域,包括订单创建、支付、配送等业务。商品管理可以是一个子领域,涵盖商品发布、库存管理、价格策略等。在订单管理领域中,可能有一个用于订单创建和支付的限界上下文,另一个用于订单配送和物流管理的限界上下文。

当一个对象由其标识(而不是属性)区分时,这种对象称为实体(Entity)。

例:最简单的,公安系统的身份信息录入,对于人的模拟,即认为是实体,因为每个人是独一无二的,且其具有唯一标识(如公安系统分发的身份证号码)。

值对象

当一个对象用于对事务进行描述而没有唯一标识时,它被称作值对象(ValueObject)。

例:比如颜色信息,我们只需要知道{“name”:“黑色”,”css”:“#000000”}这样的值信息就能够满足要求了,这避免了我们对标识追踪带来的系统复杂性。它具有不变性、相等性和可替换性。

聚合是由紧密关联的实体和值对象组成,是修改和保存数据的基本单位。每个聚合都有一个仓库,用于保存聚合的数据。

聚合有一个聚合根和上下文边界,边界根据业务需求和内聚原则,定义了聚合应该包含哪些实体和值对象,而聚合之间是松耦合的,这样设计的微服务,会很自然地实现高内聚、低耦合。

聚合在DDD分层架构中是领域层的一部分,领域层可以包含多个聚合,共同实现核心业务逻辑。实体在聚合内以充血模型实现业务能力,保证业务逻辑的高内聚。

跨多个实体的业务逻辑通过领域服务来实现,跨多个聚合的业务逻辑通过应用服务来实现。

聚合是一个非常重要的概念,核心领域往往都需要用聚合来表达。其次,聚合在技术上有非常高的价值,可以指导详细设计。

聚合由根实体,值对象和实体组成。聚合根可以理解为是一系列聚合的管理者,他具有全局唯一id。聚合之间协作的时候,聚合根是对外的接口人,通过自己的ID关联其他聚合。外部对象不能直接访问聚合内实体。

一些重要的领域行为或操作,可以归类为领域服务。它既不是实体,也不是值对象的范畴。可以理解为domainservice中的一些内聚操作

聚合根应该是一个聚合中最重要的实体,其他实体和值对象通过聚合根关联。我们要考虑在这个业务中,哪个实体在业务中扮演核心角色。可以有效的管理封装聚合的行为。

聚合应该尽可能的小,只包含必须由聚合根直接管理的实体和值对象。提高内聚性。

聚合根应该封装聚合内部的业务规则,任何对聚合内部数据的修改,都应该通过聚合根的方法进行访问,这样聚合根才能保证聚合的状态的一致性。

聚合的状态应该是最小的一致性边界,保持自身聚合的一致性,事务应该在单个聚合范围内实现,不能跨聚合操作。

我们以电商平台的订单系统为例,看看聚合和聚合根是如何设计和使用的。

在订单系统中,订单通常作为聚合根,因为订单是整个业务流程中最核心的业务对象。

订单聚合包括多个实体对象,如订单明细、支付信息、收货信息等。聚合中包含了实体也包含了值对象(DP)。

订单明细:聚合内的实体,每个订单明细代表订单中的一个购买项。它包括商品ID、购买数量、单价和小计。订单明细与订单紧密关联,其生命周期由订单聚合根管理。

收货信息:通常是一个值对象,包含省、城市、街道和邮编等信息。因为它没有独立的标识,仅仅描述了一个地理位置。

通过设计正确的聚合,订单系统的业务操作会非常清晰,并能够集中管理。

下面列举一些常见的业务操作,介绍聚合是如何被使用的。

当客户选完商品,并提交订单时,系统会触发订单创建的流程。

系统首先创建一个新的订单聚合实例,此实例以订单为聚合根。订单聚合根包含了必要的信息,如订单编号、订单初始状态等。

客户选定的每个商品都会作为订单明细,添加到订单中。每个订单明细实体包括商品ID、购买数量和单价等信息。这些订单明细在创建过程中由订单聚合根动态管理,确保数据的完整性。

客户提供的收货地址被创建为值对象,并与订单聚合关联。同时,初始化的支付信息也会被设置为一个实体,包括支付方式和支付状态等信息。

这边我想强调一下,值对象是不可变的。当订单创建完毕后,这个商品的详细信息或者价格发生了更改,不应该影响到这条订单里面的数据,也就是可以理解为,订单创建的瞬间,里面的值对象应该是快照。

支付成功后,订单聚合根会将订单状态更新为“已支付”,这是通过聚合内部的业务逻辑完成,确保所有数据一致。

在订单准备发货时,订单聚合根会验证存储的收货地址信息的完整性和准确性。如果地址不完整,可能会要求客户提供更多信息,或进行二次确认。

一旦发货地址验证无误,且商品准备就绪,订单聚合根将订单状态更新为“已发货”。随后,实际物流操作开始进行,并在系统中记录和跟踪发货的过程信息。

领域驱动设计(DDD)是软件开发的一场革命,它将我们从技术细节的泥潭中解放出来,让我们重新聚焦于业务本身。DDD不是一套僵化的规则,而是一种思想,一种将业务领域知识置于软件开发核心的哲学。

通过DDD,我们构建的不再是简单的代码,而是一个个鲜活的业务模型。这些模型,如实体、值对象、聚合,它们携带着业务的DNA,它们的行为和属性定义了业务的逻辑和流程。这种以业务为中心的建模方式,让软件系统更加贴近真实世界,更加易于理解和维护。

DDD提倡的分层架构,将业务逻辑与技术实现解耦,使得系统更加灵活,更易于适应变化。它鼓励我们在不同的层次上使用最适合的技术,而不必为了技术而牺牲业务的清晰性和可维护性。

限界上下文的概念,更是DDD中的点睛之笔。它教会我们如何在庞大的业务领域中划定边界,定义清晰的业务规则和模型,同时通过上下文映射来实现不同业务领域间的协调和交互。

而充血模型的应用,则是对传统贫血模型的一种颠覆。它将业务逻辑重新赋予领域对象,让对象本身具备行为和决策能力,从而提升了代码的内聚性和可读性。

在微服务架构大行其道的今天,DDD的原则和模式更显价值。它指导我们在服务拆分时保持业务的完整性,避免业务逻辑的碎片化,构建出既灵活又健壮的微服务系统。

DDD是一种精神,一种追求业务与技术和谐统一的精神。它不是终点,而是起点,引导我们在软件开发的道路上不断探索和前行。拥抱DDD,就是拥抱一种更加人性化、更加富有创造力的软件开发方式。

THE END
1.HTML实例本例演示如何在 HTML 源代码中插入隐藏的注释。 背景颜色 本例演示如何为 HTML 页面添加背景颜色。 本例演示:如何使用三份不同的文档制作一个垂直框架。 水平框架 本例演示:如何使用三份不同的文档制作本例演示如何在网页中显示图像。 从不同的位置插入图片 本例演示如何将其他文件夹或服务器的图片显示https://www.w3school.com.cn/example/html_examples.asp
2.jQuery网页特效最全网页模板和网站模板jQuery代码17素材网主要收集jQuery网页特效、jQuery网页代码、网站模板、网页模板、企业模板、商城模板、图标等素材,为html网站模板开发人员提供高效率的工作方式。https://www.17sucai.com/
3.Arduino库教程EthernetWebClient样例代码 /* Web client This sketch connects to a website (http://www.google.com) using an Arduino Wiznet Ethernet shield. Circuit: * Ethernet shield attached to pins 10, 11, 12, 13 created 18 Dec 2009 by David A. Mellis modified 9 Apr 2012 https://www.ncnynl.com/archives/201608/569.html
4.H5制作二维码扫描和解析的代码实例H5教程web端或者是 h5端可以直接完成扫码的工作; 3.缺点: 图片不清晰很容易解析失败(拍照扫描图片需要镜头结构在网页上面是有固定的显示样式,为了能够自定义按钮样式,我们可以按照下面的示例代码结构嵌套代码 样例展示 1.呼起前的页面 2.呼起后的页面 【相关推荐】 1. Html5免费视频教程 2. H5完成多图片https://m.php.cn/faq/363143.html
5.自动生成工具范文10篇(全文)国内外许多大型的软件公司为了解决代码的重用问题, 都有自己的解决方案, 有的从开发框架和类库入手来解决系统的复杂性和代码量过多的问题, 有的从编程模式入手, 通过新的编程方式来解决这类问题;还有的通过代码生成工具方式来解决重复性问题。其中采用代码自动生成工具成为提高开发效率的一种很好的选择。代码生成工具https://www.99xueshu.com/w/ikeyqz1sk4o9.html
6.androidwebview加载网页样例webview资源在Android开发中,WebView是一个非常重要的组件,它允许我们在应用程序中内嵌网页内容,实现与网页的交互。本文将深入探讨`Android webview`的相关知识点,并结合提供的代码示例进行详细解析。 首先,WebView的基本 5星 · 资源好评率100% webview的简单样例 在Android开发中,WebView是一个非常重要的组件,它允许我们https://download.csdn.net/download/q610098308/8886225
7.网页拖拽元素生成java代码网页实现拖拽功能网页拖拽元素生成java代码 网页实现拖拽功能,Javascript的特点是dom的处理与网页效果,大多数情况我们只用到了这个语言的最简单的功能,比如制作图片轮播/网页的tab等等,这篇文章将向你展示如何在自己的网页上制作拖拽.有很多理由让你的网站加入拖拽功能,最简单的一个是https://blog.51cto.com/u_16099211/8807477
8.超全整理:程序员都在用什么工具?any-rule 维护了一个常用正则表达式合集,并且本身是一个支持 Web/VS Code/idea/Alfred Workflow 多平台的正则表达式工具。 4. tool.lu(在线工具): https://tool.lu 程序员总是有很多小工具要使用,比如图片、Base64 编码、Markdown 编辑器时间戳转换,进制转换等,在线运行各种语言代码。这个网站包含了太多程序员需https://xie.infoq.cn/article/3808624e50341691b5e44c647
9.公司网站建设总结/学生个人网页制作成品公司网站建设总结,学生个人网页制作成品,如何建国际商城网站,团队云智能网站建设from me: web动画能够带来一个非常酷炫的效果,能够让页面有一个更好的用户体验。对于良好的动画性能没有高招,除了将大量的时间放在测试和优化,当然最重要的还是要易于维护。 流畅web动画的十大法则: 不要改变除了opacity和trans… http://www.mhkc.cn/news/375229.html
10.大学生html网页制作——食品香菇品牌网页制作html+css+js+视频品牌类网页制作期末大作业html+css共5个页面,网页代码包含表达元素、图片等内容,logo,导航栏切换, 原始HTML+CSS页面设计,web大学生网页设计作业源码,这是一个不错的网页制作,画面精明,非常话合初学者学习使用。 发布于 2024-12-16 14:47?IP 属地江苏 https://zhuanlan.zhihu.com/p/12663593915
11.网页设计与制作案例教程(HTML5+CSS3)全套PPT课件(436页)项目1 走进网页世界 1.1 任务1:制作“念奴娇?赤壁怀古” 网页 1.2 前端修炼手册:网页基础知识 1.3 任务2:制作“苏轼介绍”网页 1.4 前端修炼手册:Dreamweaver 2021的 工作界面和使用技巧 1.5 能力提升:制作“青春颂歌”网页 1.6 能力挑战:制作“速度滑冰”网页目录1.1 任务1:制作“念奴娇?赤壁怀古”网页1.1 任务1:https://m.book118.com/html/2023/0317/5242323311010123.shtm
12.盘点三款高可用的机器学习模型web页面化的工具(一)python︱写markdown一样写网页,代码快速生成web工具:streamlit介绍(一)python︱写markdown一样写网页,代码快速生成web工具:streamlit 重要组件介绍(二)python︱写markdown一样写网页,代码快速生成web工具:streamlit 展示组件(三)python︱写markdown一样写网页,代码快速生成web工具:streamlit lay-out布局(四)python︱写marhttps://cloud.tencent.com/developer/article/2169864
13.Swift一、实现一个静态的文件目录网站(Static Website) GCDWebServer 内置的处理程序可以递归服务端目录,从而实现一个静态的文件目录浏览功能(只读)。同时我们还可以自由设置“Cache - Control”头。 1,样例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import UIKit class ViewController: UIhttps://www.hangge.com/blog/cache/detail_1563.html
14.网页设计论文[2]李艳新.网页设计中计算机图像处理技术的应用价值[J].电子技术与软件工程,20xx(09). 网页设计论文2 摘要:DIV+CSS是Web设计标准,随着Web2.0标准化设计理念的普及,国内很多大型站采用DIV+CSS网页布局制作方法。从实际应用情况证明,该技术具有代码简洁、表现和内容相分离等优势。 https://www.ruiwen.com/lunwen/6161857.html
15.WebGL编程指南的书本源代码webGL编程示例源码 WebGL 是一项在网页上渲染三维图形的技术,也是HTML5 草案的一部分。 《WebGL编程指南》的主要篇幅讲解了WebGL 原生API 和三维图形学的基础知识,包括渲染管线、着色器、矩阵变换、着色器编程语言(GLSL ES)等等,也讲解了使用WebGL 渲染三维场景的一般技巧,如光照、阴影、雾化等等。《WebGL编程指南https://www.iteye.com/resource/qfire-10371055
16.向web中添加矢量图形本文提供了矢量图形和 SVG 的简单教程,让你了解他们的作用,以及如何在网页中引入 SVG。本文并非学习 SVG 的完整教程,只是一个指南,让你在 Web 上遇到 SVG 时知道它是什么。所以不要因为觉得你不是一个 SVG 专家而担心。如果你想了解更多它的工作原理,我们在下面列出了一些可能会帮助你的链接。 http://developer.mozilla.org/zh-CN/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web
17.rss阅读器java代码,开源rss阅读器创新互联公司主要从事网站设计制作、成都网站设计、网页设计、企业做网站、公司建网站等业务。立足成都服务古塔,10年网站建设经验,价格优惠、服务专业,欢迎来电咨询RSS 2.0 以下是RSS 2.0的代码样例 !-- XML版本和字符集 -- ?xml version="1.0"? !-- RSS版本 -- rss version="2.0" !-- 以下为频道信息及新http://chengdu.cdxwcx.cn/article/hcoghs.html
18.代码图形化的设计和执行爬虫任务。别名:ServiceWrapper面向Web易采集/EasySpider: Visual Code-Free Web Crawler 一个可视化浏览器自动化测试/数据采集/爬虫软件,可以使用图形化界面,无代码可视化的设计和执行任务。只需要在网页上选择自己想要操作的内容并根据提示框操作即可完成任务的设计和执行。同时软件还可以单独以命令行的方式进行执行,从而可以很方便的嵌入到其他系统中。 https://github.com/NaiboWang/EasySpider
19.Airflow代码示例开源大数据平台EMapReduce(EMR)本文通过示例为您介绍如何使用OSS Sensor、WebHDFS Sensor、Spark Operator、Hive Operator、Bash Operator和给DAG配置告警。 背景信息 本文为您介绍以下代码示例: 使用OSS Senser 使用WebHDFS Sensor 使用Spark Operator 使用Hive Operator 使用Bash Operator 使用ZeppelinOperator 使用JupyterOperator 给DAG配置告警 前提条件https://help.aliyun.com/zh/emr/emr-on-ecs/user-guide/sample-code-1
20.单点登录我用J2EE的技术(JSP和Servlet)完成了一个具有Web-SSO的简单样例。样例包含一个身份认证的服务器和两个简单的 Web应用,使得这两个 Web应用通过统一的身份认证服务来完成Web-SSO的功能。此样例所有的源代码和二进制代码都可以从网站地址http://gceclub.sun.com.cn/wangyu/下载。 样例部 署和运行的环境有一定的要https://www.coder100.com/index/index/content/id/1491786
21.Web应用(精选十篇)随着应用和服务的兴盛, 网页浏览的安全问题也日益凸显, 各种针对于网页服务器端的攻击层出不穷, 网页的信息容易遭到篡改并植入有害代码, 个人信息大量泄露利用浏览器的漏洞的挂马网站大量泛滥, 据相关安全机构统计, 80%的电脑中毒都来源于用户浏览了带病毒的网页和链接, 网页攻击成为黑客入侵的主要手段之一。 2 WEBhttps://www.360wenmi.com/f/cnkey0nsxmsc.html
22.SpringMVC通过模型视图ModelAndView渲染视图的实现javaspring.mvc.view.prefix=/WEB-INF/jsp/ spring.mvc.view.suffix=.jsp C.为了定制InternalResourceViewResolver初始化,可以在配置文件application.properties(或yml文件)中进行配置,代码如上。 D.它会以前缀(prefix)和后缀(suffix)以及视图名称组成全路径定位视图。 https://www.jb51.net/article/201086.htm
23.全国计算机一级考试试题及答案(精选14套)(5)将制作好的演示文稿以文件名为Web,文件类型为演示文稿(*.ppt)保存,同时另存为Web页Web.htm,文件均存放于考生文件夹下的Web站点中; (6)为下框架网页中文字点击参考创建超级链接,指向Web.htm,目标框架为新建窗口。 7.将所有修改过的网页以原文件名保存,文件均存放于考生文件夹下Web站点中。 样页: 第3题https://www.oh100.com/kaoshi/ncre1/tiku/231476.html