自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

DDD 很難,推薦一套小白也能輕松落地的方案!

開發(fā)
本文我們按照 DDD 的分層原則詳細(xì)地落地了一個user添加和查詢功能,并實現(xiàn)支持多種持久化機制(MySQL 和 DynamoDB)的倉儲層設(shè)計。

DDD是微服務(wù)中經(jīng)常用到的一種架構(gòu)方式,在實際工作中,我們該如何快速落地一個 DDD工程呢?這篇文章,我們將手把手帶你落地一個 DDD項目,不管你有沒有 DDD經(jīng)驗,都可以輕松使用。

在開始我們的文章之前,我們還是要簡單的了解下 DDD是什么,幫助我們下面更好地理解代碼工程。

一、什么是DDD?

DDD,全稱 Domain-Driven Design,翻譯為領(lǐng)域驅(qū)動設(shè)計,它是一種軟件開發(fā)方法論,由埃里克·埃文斯(Eric Evans) 在其2003年出版的同名書籍中提出。DDD旨在通過密切關(guān)注復(fù)雜軟件系統(tǒng)的核心業(yè)務(wù)領(lǐng)域,將業(yè)務(wù)需求與技術(shù)實現(xiàn)緊密結(jié)合,從而提高軟件的可維護性、可擴展性和靈活性。

1. DDD 的核心理念

DDD 以領(lǐng)域為核心,強調(diào)將業(yè)務(wù)領(lǐng)域作為軟件開發(fā)的核心,致力于深入理解業(yè)務(wù)需求和業(yè)務(wù)規(guī)則,通過建模來反映實際業(yè)務(wù)問題。

2. 統(tǒng)一語言

DDD使得開發(fā)團隊和業(yè)務(wù)專家共同使用的一種準(zhǔn)確、一致的語言(Ubiquitous Language),用于描述業(yè)務(wù)領(lǐng)域中的概念、流程和規(guī)則,減少溝通障礙,提高理解一致性。

3. 戰(zhàn)略設(shè)計與戰(zhàn)術(shù)設(shè)計

DDD 分為戰(zhàn)略設(shè)計和戰(zhàn)術(shù)設(shè)計兩部分:

  • 戰(zhàn)略設(shè)計:關(guān)注整個系統(tǒng)的高層次結(jié)構(gòu)和模塊劃分,定義不同的子域(Subdomain)和上下文邊界(Bounded Context)。
  • 戰(zhàn)術(shù)設(shè)計:關(guān)注特定上下文內(nèi)的細(xì)節(jié),實現(xiàn)領(lǐng)域模型和相關(guān)組件。

說實話,DDD的理論確實很燒腦,我們會在后續(xù)的文章中慢慢拆解。不管怎樣,在對 DDD有了簡單的了解之后,我們要進(jìn)入今天的核心部分:DDD代碼實操。

本文目標(biāo):使用DDD + SpringBoot + JPA + 雙數(shù)據(jù)源(MySQL + DynamoDB)實現(xiàn)對 user表進(jìn)行添加和查詢功能,完全適合小白操作。

二、項目整體結(jié)構(gòu)

首先,我們先看下整個工程建的主要模塊以及模塊之間的依賴關(guān)系:

  • domain:核心領(lǐng)域模型和業(yè)務(wù)邏輯。
  • repository:倉儲接口定義。
  • application:應(yīng)用服務(wù)層,協(xié)調(diào)領(lǐng)域?qū)ο蠛蛡}儲。
  • infrastructure:基礎(chǔ)設(shè)施層,包括具體的倉儲實現(xiàn)(MySQL 和 DynamoDB)、配置等。
  • config:獨立的配置模塊(可選,視項目復(fù)雜程度而定)。
  • api(或 web):入口層,如 REST API 控制器,主要處理外部接口請求。

模塊結(jié)構(gòu)如下:

ddd-project/
├── build.gradle
├── settings.gradle
├── domain/
│   └── build.gradle
├── repository/
│   └── build.gradle
├── application/
│   └── build.gradle
├── infrastructure/
│   ├── build.gradle
│   ├── persistence-mysql/
│   │   └── build.gradle
│   └── persistence-dynamodb/
│       └── build.gradle
├── config/
│   └── build.gradle
└── api/
    └── build.gradle

三、項目模塊詳解

1. Gradle 配置

(1) 根項目 settings.gradle

在根項目的 settings.gradle 中,包含所有子模塊:

rootProject.name = 'ddd-project'

include 'domain'
include 'repository'
include 'application'
include 'infrastructure'
include 'infrastructure:persistence-mysql'
include 'infrastructure:persistence-dynamodb'
include 'config'
include 'api'

(2) 根項目 build.gradle

根項目的 build.gradle 通常用于定義全局的插件和依賴管理。

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.0.0' apply false
    id 'io.spring.dependency-management' version '1.1.0' apply false
}

allprojects {
    group = 'com.example'
    version = '1.0.0'
    
    repositories {
        mavenCentral()
    }
}

subprojects {
    apply plugin:'java'
    
    sourceCompatibility = '17'
    targetCompatibility = '17'

    dependencies {
        // 通用依賴,可以在此處添加
        implementation 'org.springframework.boot:spring-boot-starter'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
    }

    // 統(tǒng)一的測試任務(wù)配置等(可選)
}

2. 各子模塊配置

(1) domain 模塊

功能:定義核心領(lǐng)域模型和業(yè)務(wù)邏輯。

domain/build.gradle:

dependencies {
    // 無需依賴其他模塊,專注于領(lǐng)域邏輯
}

示例代碼:

// domain/src/main/java/com/example/domain/User.java
package com.example.domain;

publicclass User {
    private String id;
    private String name;
    private String email;

    // 構(gòu)造函數(shù)、Getters 和 Setters

    public User() {}

    public User(String id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    // getters and setters
    public String getId() {
        return id;
    }

    // ... 其他 getters 和 setters
}

(2) repository 模塊

功能:定義倉儲接口,供應(yīng)用層和基礎(chǔ)設(shè)施層引用。

repository/build.gradle:

dependencies {
    implementation project(':domain')
}

示例代碼:

// repository/src/main/java/com/example/repository/UserRepository.java
package com.example.repository;

import com.example.domain.User;
import java.util.Optional;
import java.util.List;

public interface UserRepository {
    void save(User user);
    Optional<User> findById(String id);
}

(3) application 模塊

功能:實現(xiàn)應(yīng)用服務(wù),協(xié)調(diào)領(lǐng)域模型和倉儲接口。

application/build.gradle:

dependencies {
    implementation project(':domain')
    implementation project(':repository')
    implementation 'org.springframework.boot:spring-boot-starter'
}

示例代碼:

// application/src/main/java/com/example/application/UserService.java
package com.example.application;

import com.example.domain.User;
import com.example.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
publicclass UserService {

    privatefinal UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository){
        this.userRepository = userRepository;
    }

    public void createUser(User user){
        userRepository.save(user);
    }

    public Optional<User> getUserById(String id){
        return userRepository.findById(id);
    }
}

(4) infrastructure 模塊

功能:實現(xiàn)基礎(chǔ)設(shè)施組件,包括具體的倉儲實現(xiàn)。

infrastructure/build.gradle:

dependencies {
    implementation project(':repository')
    implementation 'org.springframework.boot:spring-boot-starter'
}

① infrastructure:persistence-mysql子模塊

功能:實現(xiàn) MySQL 的具體倉儲。

infrastructure/persistence-mysql/build.gradle:

plugins {
    id 'org.springframework.boot'
    id 'io.spring.dependency-management'
}

dependencies {
    implementation project(':domain')
    implementation project(':repository')
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'mysql:mysql-connector-java'
    
    // 可選:MapStruct 用于對象映射
    implementation 'org.mapstruct:mapstruct:1.5.5.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
}

示例代碼:


// infrastructure/persistence-mysql/src/main/java/com/example/infrastructure/persistence/mysql/UserEntity.java
package com.example.infrastructure.persistence.mysql;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "users")
publicclass UserEntity {
    @Id
    private String id;
    private String name;
    private String email;

    // 構(gòu)造函數(shù)、Getters 和 Setters

    public UserEntity() {}

    public UserEntity(String id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    // getters and setters
}
// infrastructure/persistence-mysql/src/main/java/com/example/infrastructure/persistence/mysql/ JpaUserRepository.java
package com.example.infrastructure.persistence.mysql;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface JpaUserRepository extends JpaRepository<UserEntity, String> {
}
// infrastructure/persistence-mysql/src/main/java/com/example/infrastructure/persistence/mysql/MySQLUserRepository.java
package com.example.infrastructure.persistence.mysql;

import com.example.domain.User;
import com.example.repository.UserRepository;
import org.springframework.stereotype.Repository;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Optional;
import java.util.List;
import java.util.stream.Collectors;

@Repository
publicclass MySQLUserRepository implements UserRepository {

    privatefinal JpaUserRepository jpaUserRepository;

    @Autowired
    public MySQLUserRepository(JpaUserRepository jpaUserRepository){
        this.jpaUserRepository = jpaUserRepository;
    }

    @Override
    public void save(User user) {
        UserEntity entity = new UserEntity(user.getId(), user.getName(), user.getEmail());
        jpaUserRepository.save(entity);
    }

    @Override
    public Optional<User> findById(String id) {
        Optional<UserEntity> entityOpt = jpaUserRepository.findById(id);
        return entityOpt.map(entity -> new User(entity.getId(), entity.getName(), entity.getEmail()));
    }
}

② infrastructure:persistence-dynamodb 子模塊

功能:實現(xiàn) DynamoDB 的具體倉儲。

infrastructure/persistence-dynamodb/build.gradle:

plugins {
    id 'org.springframework.boot'
    id 'io.spring.dependency-management'
}

dependencies {
    implementation project(':domain')
    implementation project(':repository')
    implementation 'software.amazon.awssdk:dynamodb:2.20.0'
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.0'
    implementation 'org.springframework.boot:spring-boot-starter'
}

示例代碼:

// infrastructure/persistence-dynamodb/src/main/java/com/example/infrastructure/persistence/dynamodb/DynamoDBUserRepository.java
package com.example.infrastructure.persistence.dynamodb;

import com.example.domain.User;
import com.example.repository.UserRepository;
import org.springframework.stereotype.Repository;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;

import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Optional;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Repository
publicclass DynamoDBUserRepository implements UserRepository {

    privatestaticfinal String TABLE_NAME = "Users";

    privatefinal DynamoDbClient dynamoDbClient;
    privatefinal ObjectMapper objectMapper;

    @Autowired
    public DynamoDBUserRepository(DynamoDbClient dynamoDbClient){
        this.dynamoDbClient = dynamoDbClient;
        this.objectMapper = new ObjectMapper();
    }

    @Override
    public void save(User user) {
        try {
            String json = objectMapper.writeValueAsString(user);
            Map<String, Object> map = objectMapper.readValue(json, Map.class);
            Map<String, AttributeValue> item = map.entrySet().stream()
                    .collect(Collectors.toMap(
                            Map.Entry::getKey,
                            e -> AttributeValue.builder().s(e.getValue().toString()).build()
                    ));

            PutItemRequest request = PutItemRequest.builder()
                    .tableName(TABLE_NAME)
                    .item(item)
                    .build();

            dynamoDbClient.putItem(request);
        } catch (Exception e) {
            thrownew RuntimeException("Failed to save user to DynamoDB", e);
        }
    }

    @Override
    public Optional<User> findById(String id) {
        GetItemRequest request = GetItemRequest.builder()
                .tableName(TABLE_NAME)
                .key(Map.of("id", AttributeValue.builder().s(id).build()))
                .build();

        GetItemResponse response = dynamoDbClient.getItem(request);
        if (response.hasItem()) {
            try {
                String json = objectMapper.writeValueAsString(response.item());
                User user = objectMapper.readValue(json, User.class);
                return Optional.of(user);
            } catch (Exception e) {
                thrownew RuntimeException("Failed to parse user from DynamoDB", e);
            }
        }
        return Optional.empty();
    }
}

③ DynamoDB 客戶端配置

在 infrastructure:persistence-dynamodb 子模塊中配置 DynamoDB 客戶端 Bean。

// infrastructure/persistence-dynamodb/src/main/java/com/example/infrastructure/persistence/dynamodb/DynamoDBConfig.java
package com.example.infrastructure.persistence.dynamodb;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.regions.Region;

@Configuration
publicclass DynamoDBConfig {
    @Bean
    public DynamoDbClient dynamoDbClient() {
        return DynamoDbClient.builder()
                .region(Region.US_EAST_1) // 根據(jù)實際情況選擇區(qū)域
                .build();
    }
}

(5) config 模塊(可選)

功能:集中管理項目配置,例如選擇使用的倉儲實現(xiàn)、數(shù)據(jù)庫配置等。

config/build.gradle:

dependencies {
    implementation project(':application')
    implementation project(':infrastructure:persistence-mysql')
    implementation project(':infrastructure:persistence-dynamodb')
    implementation 'org.springframework.boot:spring-boot-starter'
}

示例代碼:

// config/src/main/java/com/example/config/RepositoryConfig.java
package com.example.config;

import com.example.repository.UserRepository;
import com.example.infrastructure.persistence_mysql.MySQLUserRepository;
import com.example.infrastructure.persistence_dynamodb.DynamoDBUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
publicclass RepositoryConfig {

    @Value("${app.repository.type}")
    private String repositoryType;

    privatefinal MySQLUserRepository mySQLUserRepository;
    privatefinal DynamoDBUserRepository dynamoDBUserRepository;

    @Autowired
    public RepositoryConfig(MySQLUserRepository mySQLUserRepository, DynamoDBUserRepository dynamoDBUserRepository){
        this.mySQLUserRepository = mySQLUserRepository;
        this.dynamoDBUserRepository = dynamoDBUserRepository;
    }

    @Bean
    public UserRepository userRepository() {
        if ("mysql".equalsIgnoreCase(repositoryType)) {
            return mySQLUserRepository;
        } elseif ("dynamodb".equalsIgnoreCase(repositoryType)) {
            return dynamoDBUserRepository;
        } else {
            thrownew IllegalArgumentException("Unsupported repository type: " + repositoryType);
        }
    }
}

**application.properties**(在 api 模塊或根模塊)

# application.properties
app.repository.type=mysql
# 或者
# app.repository.type=dynamodb

(6) api 模塊

功能:作為應(yīng)用的入口,處理外部請求(如 REST API)。

api/build.gradle:

plugins {
    id 'org.springframework.boot'
    id 'io.spring.dependency-management'
}

dependencies {
    implementation project(':application')
    implementation project(':config')
    implementation 'org.springframework.boot:spring-boot-starter-web'
}

示例代碼:

// api/src/main/java/com/example/api/UserController.java
package com.example.api;

import com.example.application.UserService;
import com.example.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/users")
publicclass UserController {

    privatefinal UserService userService;

    @Autowired
    public UserController(UserService userService){
        this.userService = userService;
    }

    @PostMapping
    public void createUser(@RequestBody User user){
        userService.createUser(user);
    }

    @GetMapping("/{id}")
    public Optional<User> getUserById(@PathVariable String id){
        return userService.getUserById(id);
    }
}

4. 模塊間依賴關(guān)系圖

domain
   ↑
repository
   ↑
application
   ↑
infrastructure
   ↑
config
   ↑
api
  • domain 是最底層,其他模塊依賴于它。
  • repository 依賴于 **domain**。
  • application 依賴于 repository 和 **domain**。
  • infrastructure 依賴于 repository 和 **domain**,實現(xiàn)具體倉儲。
  • config 依賴于 application 和 **infrastructure**,進(jìn)行配置管理。
  • api 依賴于 application 和 **config**,作為應(yīng)用入口。

四、實施步驟詳解

1. 創(chuàng)建各個模塊

使用 Gradle 命令或 IDE 創(chuàng)建各個模塊。例如,使用命令行:

mkdir ddd-project
cd ddd-project
gradle init --type basic
# 創(chuàng)建子模塊目錄
mkdir domain repository application infrastructure
mkdir infrastructure/persistence-mysql infrastructure/persistence-dynamodb
mkdir config api

然后,在各個子模塊目錄下創(chuàng)建相應(yīng)的 build.gradle 文件并添加內(nèi)容,如上所示。

2. 配置依賴關(guān)系

確保每個子模塊的 build.gradle 文件中正確地聲明依賴關(guān)系。例如,在 application 模塊的 build.gradle 中:

dependencies {
    implementation project(':domain')
    implementation project(':repository')
    implementation 'org.springframework.boot:spring-boot-starter'
}

類似地,在其他模塊中聲明所需的依賴。

3. 配置 SpringBoot

在 api 模塊中,添加 SpringBoot應(yīng)用的主類:

// api/src/main/java/com/example/api/MyDddProjectApplication.java
package com.example.api;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = "com.example")
public class MyDddProjectApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyDddProjectApplication.class, args);
    }
}

說明:使用 @SpringBootApplication 注解并設(shè)置 scanBasePackages 為 com.example,確保 Spring 能掃描到所有子模塊中的組件。

4. 配置應(yīng)用屬性

在 api 模塊中創(chuàng)建 src/main/resources/application.properties,并添加必要的配置:

# MySQL 配置
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=secret
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

# 倉儲選擇
app.repository.type=mysql
# 或者
# app.repository.type=dynamodb

# DynamoDB 配置(如適用)
# aws.accessKeyId=YOUR_ACCESS_KEY
# aws.secretAccessKey=YOUR_SECRET_KEY
# aws.region=us-east-1

5. 構(gòu)建和運行

在根項目目錄下,運行以下命令以構(gòu)建和運行應(yīng)用:

./gradlew build
./gradlew :api:bootRun

確保你的 MySQL 和 DynamoDB(如果選擇使用)都已正確配置和運行。

五、項目優(yōu)化

1. 使用 Spring Profiles

為了更靈活地在不同環(huán)境(如開發(fā)、測試、生產(chǎn))中選擇倉儲實現(xiàn),可以使用 Spring Profiles。

示例:

在 MySQLUserRepository 和 DynamoDBUserRepository 上添加 @Profile 注解。

// MySQLUserRepository.java
@Repository
@Profile("mysql")
public class MySQLUserRepository implements UserRepository {
    // ...
}

// DynamoDBUserRepository.java
@Repository
@Profile("dynamodb")
public class DynamoDBUserRepository implements UserRepository {
    // ...
}

在 application.properties 中指定活躍配置:

spring.profiles.active=mysql
# 或者
# spring.profiles.active=dynamodb

2. 使用 MapStruct進(jìn)行對象映射

手動在倉儲實現(xiàn)中轉(zhuǎn)換領(lǐng)域?qū)ο蠛统志没瘜ο罂赡芊爆崳褂?MapStruct 可以簡化這一過程。

示例:

添加 MapStruct 依賴(已在 persistence-mysql 模塊中添加)。

定義映射接口:

// infrastructure/persistence-mysql/src/main/java/com/example/infrastructure/persistence/mysql/UserMapper.java
package com.example.infrastructure.persistence.mysql;

import com.example.domain.User;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    UserEntity toEntity(User user);
    User toDomain(UserEntity entity);
}

在 MySQLUserRepository 中使用 UserMapper 進(jìn)行轉(zhuǎn)換:

// MySQLUserRepository.java
package com.example.infrastructure.persistence.mysql;

import com.example.domain.User;
import com.example.repository.UserRepository;
import org.springframework.stereotype.Repository;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Optional;
import java.util.List;
import java.util.stream.Collectors;

@Repository
@Profile("mysql")
publicclass MySQLUserRepository implements UserRepository {

    privatefinal JpaUserRepository jpaUserRepository;
    privatefinal UserMapper userMapper = UserMapper.INSTANCE;

    @Autowired
    public MySQLUserRepository(JpaUserRepository jpaUserRepository){
        this.jpaUserRepository = jpaUserRepository;
    }

    @Override
    public void save(User user) {
        UserEntity entity = userMapper.toEntity(user);
        jpaUserRepository.save(entity);
    }

    @Override
    public Optional<User> findById(String id) {
        Optional<UserEntity> entityOpt = jpaUserRepository.findById(id);
        return entityOpt.map(userMapper::toDomain);
    }
}

3. 增加測試模塊

為每個模塊編寫單元測試和集成測試,確保各部分功能正常。

4. 使用依賴注入選擇倉儲實現(xiàn)

在 config 模塊中動態(tài)選擇倉儲實現(xiàn),或使用工廠模式進(jìn)一步封裝。

六、總結(jié)

本文,我們沒有講解 DDD那些燒腦的理論知識,而是按照 DDD 的分層原則詳細(xì)地落地了一個user添加和查詢功能,并實現(xiàn)支持多種持久化機制(MySQL 和 DynamoDB)的倉儲層設(shè)計。只要你有過 MVC 的 web開發(fā)經(jīng)驗,應(yīng)該可以快速理解上述 DDD的代碼工程。

對于 DDD模塊化設(shè)計帶來的好處,可以總結(jié)為以下幾點:

  • 高內(nèi)聚、低耦合:每個模塊都有明確的職責(zé),模塊之間通過接口進(jìn)行通信,降低了耦合度。
  • 易于擴展:未來添加新的持久化機制(如 PostgreSQL、Redis 等)時,只需新增相應(yīng)的基礎(chǔ)設(shè)施子模塊,實現(xiàn)倉儲接口即可。
  • 團隊協(xié)作:不同團隊或開發(fā)者可以并行開發(fā)不同模塊,減少沖突和依賴問題。
  • 可維護性:清晰的模塊邊界和職責(zé)分離,使得代碼更易于理解和維護。

在實際項目中,我們可根據(jù)具體的業(yè)務(wù)需求靈活地調(diào)整模塊劃分和依賴關(guān)系,確保架構(gòu)設(shè)計既符合業(yè)務(wù)需求,又具備良好的技術(shù)基礎(chǔ)。

責(zé)任編輯:趙寧寧 來源: 猿java
相關(guān)推薦

2024-12-09 09:25:30

2019-02-20 10:22:20

監(jiān)控HDFSHadoop

2025-03-03 10:00:00

2010-06-09 17:00:43

UML試題

2015-01-19 09:37:00

2014-12-17 12:46:17

華為存儲

2022-07-10 20:45:47

React加載動畫庫

2023-03-22 23:23:25

React加載動畫庫

2009-03-03 13:00:00

虛擬化技術(shù)vmwarexen

2018-08-02 09:44:35

AIOps實踐數(shù)據(jù)

2018-07-25 18:44:35

智能硬件

2023-10-23 12:31:40

2025-03-28 09:52:08

CIGo項目

2020-06-29 09:58:29

微軟算法照片

2009-06-23 18:01:45

Ajax框架源代碼

2018-08-31 08:42:48

LinuxUnix實用程序

2023-11-29 07:17:51

微信機器人AI

2023-03-03 17:00:00

部署Linux內(nèi)核

2014-12-02 10:02:21

Android異步任務(wù)
點贊
收藏

51CTO技術(shù)棧公眾號