Wow 正在参加 2021 年度 OSC 中国开源项目评选,请投票支持!
Wow 在 2021 年度 OSC 中国开源项目评选 中已获得 {{ projectVoteCount }} 票,请投票支持!
2021 年度 OSC 中国开源项目评选 正在火热进行中,快来投票支持你喜欢的开源项目!
2021 年度 OSC 中国开源项目评选 >>> 中场回顾
Wow 获得 2021 年度 OSC 中国开源项目评选「最佳人气项目」 !
授权协议 Apache
开发语言 Kotlin 查看源码 »
操作系统 跨平台
软件类型 开源软件
所属分类 程序开发微服务框架
开源组织
地区 国产
投 递 者 Ahoo-Wang
适用人群 未知
收录时间 2023-06-02

软件简介

Wow 是基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架。

领域驱动 | 事件驱动 | 测试驱动 | 声明式设计  响应式编程  命令查询职责分离  事件源

架构图

Wow-Architecture

事件源

Wow-EventSourcing

可观测性

Wow-Observability

Spring WebFlux 集成

自动注册 命令 路由处理函数(HandlerFunction) ,开发人员仅需编写领域模型,即可完成服务开发。

Wow-OpenAPI-Swagger

测试套件:80%+ 的测试覆盖率轻而易举

Given -> When -> Expect .

Wow-CI-Flow

前置条件

  • 理解 领域驱动设计:《实现领域驱动设计》、《领域驱动设计:软件核心复杂性应对之道》
  • 理解 命令查询职责分离(CQRS)
  • 理解 事件源架构
  • 理解 响应式编程

特性

  •  Aggregate Modeling
    •  Single Class
    •  Inheritance Pattern
    •  Aggregation Pattern
  •  Saga Modeling
    •  StatelessSaga
  •  Test Suite
    •  兼容性测试规范(TCK)
    •  AggregateVerifier
    •  SagaVerifier
  •  EventSourcing
    • EventStore
      •  MongoDB (Recommend)
      •  R2dbc
        •  Database Sharding
        •  Table Sharding
      •  Redis
    • Snapshot
      •  MongoDB
      •  R2dbc
        •  Database Sharding
        •  Table Sharding
      •  ElasticSearch
      •  Redis (Recommend)
  •  CommandBus
    •  InMemoryCommandBus
    •  KafkaCommandBus (Recommend)
    •  RedisCommandBus
    •  LocalFirstCommandBus
  •  DomainEventBus
    •  InMemoryDomainEventBus
    •  KafkaDomainEventBus (Recommend)
    •  RedisDomainEventBus
    •  LocalFirstDomainEventBus
  •  StateEventBus
    •  InMemoryStateEventBus
    •  KafkaStateEventBus (Recommend)
    •  RedisStateEventBus
    •  LocalFirstStateEventBus
  •  Spring 集成
    •  Spring Boot Auto Configuration
    •  Automatically register CommandAggregate to RouterFunction
  •  可观测性
    •  OpenTelemetry
  •  OpenApi
  •  WowMetadata Generator
    •  wow-compiler

Example

Example

测试套件

80%+ 的测试覆盖率轻而易举。

Test Coverage

Given -> When -> Expect .

internal class OrderTest {

    companion object {
        val SHIPPING_ADDRESS = ShippingAddress("China", "ShangHai", "ShangHai", "HuangPu", "001")
    }

    private fun mockCreateOrder(): VerifiedStage<OrderState> {
        val tenantId = GlobalIdGenerator.generateAsString()
        val customerId = GlobalIdGenerator.generateAsString()

        val orderItem = OrderItem(
            GlobalIdGenerator.generateAsString(),
            GlobalIdGenerator.generateAsString(),
            BigDecimal.valueOf(10),
            10
        )
        val orderItems = listOf(orderItem)
        val inventoryService = object : InventoryService {
            override fun getInventory(productId: String): Mono<Int> {
                return orderItems.toFlux().filter { it.productId == productId }.map { it.quantity }.last()
            }
        }
        val pricingService = object : PricingService {
            override fun getProductPrice(productId: String): Mono<BigDecimal> {
                return orderItems.toFlux().filter { it.productId == productId }.map { it.price }.last()
            }
        }
        return aggregateVerifier<Order, OrderState>(tenantId = tenantId)
            .inject(DefaultCreateOrderSpec(inventoryService, pricingService))
            .given()
            .`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS))
            .expectEventCount(1)
            .expectEventType(OrderCreated::class.java)
            .expectStateAggregate {
                assertThat(it.aggregateId.tenantId, equalTo(tenantId))
            }
            .expectState {
                assertThat(it.id, notNullValue())
                assertThat(it.customerId, equalTo(customerId))
                assertThat(it.address, equalTo(SHIPPING_ADDRESS))
                assertThat(it.items, equalTo(orderItems))
                assertThat(it.status, equalTo(OrderStatus.CREATED))
            }
            .verify()
    }

    /**
     * 创建订单
     */
    @Test
    fun createOrder() {
        mockCreateOrder()
    }

    /**
     * 创建订单-库存不足
     */
    @Test
    fun createOrderWhenInventoryShortage() {
        val customerId = GlobalIdGenerator.generateAsString()
        val orderItem = OrderItem(
            GlobalIdGenerator.generateAsString(),
            GlobalIdGenerator.generateAsString(),
            BigDecimal.valueOf(10),
            10
        )
        val orderItems = listOf(orderItem)
        val inventoryService = object : InventoryService {
            override fun getInventory(productId: String): Mono<Int> {
                return orderItems.toFlux().filter { it.productId == productId }
                    /*
                     * 模拟库存不足
                     */
                    .map { it.quantity - 1 }.last()
            }
        }
        val pricingService = object : PricingService {
            override fun getProductPrice(productId: String): Mono<BigDecimal> {
                return orderItems.toFlux().filter { it.productId == productId }.map { it.price }.last()
            }
        }

        aggregateVerifier<Order, OrderState>()
            .inject(DefaultCreateOrderSpec(inventoryService, pricingService))
            .given()
            .`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS))
            /*
             * 期望:库存不足异常.
             */
            .expectErrorType(InventoryShortageException::class.java)
            .expectStateAggregate {
                /*
                 * 该聚合对象处于未初始化状态,即该聚合未创建成功.
                 */
                assertThat(it.initialized, equalTo(false))
            }.verify()
    }

    /**
     * 创建订单-下单价格与当前价格不一致
     */
    @Test
    fun createOrderWhenPriceInconsistency() {
        val customerId = GlobalIdGenerator.generateAsString()
        val orderItem = OrderItem(
            GlobalIdGenerator.generateAsString(),
            GlobalIdGenerator.generateAsString(),
            BigDecimal.valueOf(10),
            10
        )
        val orderItems = listOf(orderItem)
        val inventoryService = object : InventoryService {
            override fun getInventory(productId: String): Mono<Int> {
                return orderItems.toFlux().filter { it.productId == productId }.map { it.quantity }.last()
            }
        }
        val pricingService = object : PricingService {
            override fun getProductPrice(productId: String): Mono<BigDecimal> {
                return orderItems.toFlux().filter { it.productId == productId }
                    /*
                     * 模拟下单价格、商品定价不一致
                     */
                    .map { it.price.plus(BigDecimal.valueOf(1)) }.last()
            }
        }
        aggregateVerifier<Order, OrderState>()
            .inject(DefaultCreateOrderSpec(inventoryService, pricingService))
            .given()
            .`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS))
            /*
             * 期望:价格不一致异常.
             */
            .expectErrorType(PriceInconsistencyException::class.java).verify()
    }

    private fun mockPayOrder(): VerifiedStage<OrderState> {
        val verifiedStageAfterCreateOrder = mockCreateOrder()
        val previousState = verifiedStageAfterCreateOrder.stateRoot
        val payOrder = PayOrder(
            previousState.id,
            GlobalIdGenerator.generateAsString(),
            previousState.totalAmount
        )

        return verifiedStageAfterCreateOrder
            .then()
            .given()
            /*
             * 2. 当接收到命令
             */
            .`when`(payOrder)
            /*
             * 3.1 期望将会产生1个事件
             */
            .expectEventCount(1)
            /*
             * 3.2 期望将会产生一个 OrderPaid 事件 (3.1 可以不需要)
             */
            .expectEventType(OrderPaid::class.java)
            /*
             * 3.3 期望产生的事件状态
             */
            .expectEventBody<OrderPaid> {
                assertThat(it.amount, equalTo(payOrder.amount))
            }
            /*
             * 4. 期望当前聚合状态
             */
            .expectState {
                assertThat(it.address, equalTo(SHIPPING_ADDRESS))
                assertThat(it.paidAmount, equalTo(payOrder.amount))
                assertThat(it.status, equalTo(OrderStatus.PAID))
            }
            /*
             * 完成测试编排后,验证期望.
             */
            .verify()
    }

    /**
     * 支付订单
     */
    @Test
    fun payOrder() {
        mockPayOrder()
    }

    /**
     * 支付订单-超付
     */
    @Test
    fun payOrderWhenOverPay() {
        val verifiedStageAfterCreateOrder = mockCreateOrder()
        val previousState = verifiedStageAfterCreateOrder.stateRoot
        val payOrder = PayOrder(
            previousState.id,
            GlobalIdGenerator.generateAsString(),
            previousState.totalAmount.plus(
                BigDecimal.valueOf(1)
            )
        )
        verifiedStageAfterCreateOrder
            .then()
            .given()
            /*
             * 2. 处理 PayOrder 命令
             */
            .`when`(payOrder)
            /*
             * 3.1 期望将会产生俩个事件分别是: OrderPaid、OrderOverPaid
             */
            .expectEventType(OrderPaid::class.java, OrderOverPaid::class.java)
            /*
             * 3.2 期望产生的事件状态
             */
            .expectEventStream {
                val itr = it.iterator()
                /*
                 * OrderPaid
                 */
                val orderPaid = itr.next().body as OrderPaid
                assertThat(orderPaid.paid, equalTo(true))
                /*
                 * OrderOverPaid
                 */
                val orderOverPaid = itr.next().body as OrderOverPaid
                assertThat(
                    orderOverPaid.overPay,
                    equalTo(payOrder.amount.minus(previousState.totalAmount))
                )
            }
            /*
             * 4. 期望当前聚合状态
             */
            .expectState {
                assertThat(it.paidAmount, equalTo(previousState.totalAmount))
                assertThat(it.status, equalTo(OrderStatus.PAID))
            }
            .verify()
    }

    /**
     * 发货
     */
    @Test
    fun ship() {
        val verifiedStageAfterPayOrder = mockPayOrder()
        val shipOrder = ShipOrder(verifiedStageAfterPayOrder.stateRoot.id)
        verifiedStageAfterPayOrder
            .then().given()
            .`when`(shipOrder)
            .expectEventType(OrderShipped::class.java)
            /*
             * 4. 期望当前聚合状态
             */
            .expectState {
                assertThat(it.status, equalTo(OrderStatus.SHIPPED))
            }
            .verify()
    }

    @Test
    fun shipGivenUnpaid() {
        val verifiedStageAfterCreateOrder = mockCreateOrder()
        val shipOrder = ShipOrder(verifiedStageAfterCreateOrder.stateRoot.id)
        verifiedStageAfterCreateOrder.then().given()
            .`when`(shipOrder)
            .expectErrorType(IllegalStateException::class.java)
            .expectState {
                /*
                 * 验证聚合状态[未]发生变更.
                 */
                assertThat(it.paidAmount, equalTo(BigDecimal.ZERO))
                assertThat(it.status, equalTo(OrderStatus.CREATED))
            }
            .verify()
    }

    private fun mockDeleteOrder(): VerifiedStage<OrderState> {
        val verifiedStageAfterCreateOrder = mockCreateOrder()
        return verifiedStageAfterCreateOrder.then().given()
            .`when`(DeleteAggregate)
            .expectEventType(AggregateDeleted::class.java)
            .expectStateAggregate {
                assertThat(it.deleted, equalTo(true))
            }
            .verify()
    }

    @Test
    fun deleteOrder() {
        mockDeleteOrder()
    }

    @Test
    fun deleteGivenDeleted() {
        val verifiedStageAfterDelete = mockDeleteOrder()
        verifiedStageAfterDelete.then().given()
            .`when`(DeleteAggregate)
            .expectErrorType(IllegalAccessDeletedAggregateException::class.java)
            .expectError<IllegalAccessDeletedAggregateException> {
                assertThat(it.aggregateId, equalTo(verifiedStageAfterDelete.stateAggregate.aggregateId))
            }.expectStateAggregate {
                assertThat(it.deleted, equalTo(true))
            }
            .verify()
    }
}

设计

聚合建模

Single Class Inheritance Pattern Aggregation Pattern
Single Class - Modeling Inheritance Pattern- Modeling Aggregation Pattern- Modeling

加载聚合

Load Aggregate

聚合状态流

Aggregate State Flow

发送命令

Send Command

命令与事件流

Command And Event Flow

Saga - OrderProcessManager (Demo)

OrderProcessManager

展开阅读全文

代码

的 Gitee 指数为
超过 的项目

评论

点击引领话题📣 发布并加入讨论🔥
发表了资讯
09/11 14:02

Wow 2.6.0 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件溯源 更新内容 🎉 🎉 🎉 特性(Snapshot): 快照策略支持 VersionOffsetSnapshotStrategy 特性(OpenAPI): 增强异常响应定义 特性(RouteSpec): 支持 LoadEventStreamRouteSpec 特性(CommandSpec): 增强空字符串命令请求头Command-*解析为未定义 依赖: 更新 io.o...

1
2
发表了资讯
09/07 09:24

Wow 2.5.6 发布,告别 ORM、贫血模型、阻抗失配

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件溯源 更新内容 🎉 🎉 🎉 特性: OpenAPI 模块支持 ErrorInfoSchema 特性: GivenStage 支持 when 函数 特性: 新增上下文别名前缀到OpenAPI Schema以防止命名冲突 修复: 丢失 requestBodyType 定义 依赖: 更新 CosId 版本 v2.5.2 依赖: 更新 springdoc 版本 v2...

0
4
发表了资讯
08/05 15:57

Wow 2.5.0 发布,告别 ORM、贫血模型、阻抗失配

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件溯源 更新内容 🎉 🎉 🎉 支持标记忽略事件溯源接口(IgnoreSourcing) 依赖: 更新 CosId 版本 v2.4.0 依赖: 更新 io.gitlab.arturbosch.detekt 版本 v1.23.1 特性: 增强 Spring-Boot 配置提示 特性: 增强单元测试套件断言失败提示 依赖: 更新 com.google.guava...

5
10
发表了资讯
07/28 20:23

Wow 2.4.5 发布,告别贫血模型、ORM、阻抗失配

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容 🎉 🎉 🎉 依赖: 更新 CosId 版本 v2.2.6 修复: 限界上下文别名(NamedBoundedContext.alias)兼容性问题 重构: 限界上下文别名冲突检测跳过空别名 依赖: 更新 org.springframework.boot:spring-boot-dependencies 版本 v3.1.2 架构图 事件源 可观测...

1
4
发表了资讯
07/18 08:53

Wow 2.4.0 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容 🎉 🎉 🎉 依赖: 更新 CosId 版本 v2.2.2 特性: 保持 ScanAggregateHandlerFunction 扫描结果有序性 重构: 多限界上下文路由前缀 特性: AggregateVerifier 支持多领域事件流式验证 架构图 事件源 可观测性 Spring WebFlux 集成 自动注册 命令 路由...

1
5
发表了资讯
07/17 08:57

Wow 2.3.8 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容 🎉 🎉 🎉 依赖: 更新 kotlin 版本 v1.9.0 依赖: 更新 opentelemetry 版本 v1.28.0 特性: 自动新增 operator 到 ReadOnlyStateAggregate 特性: 新增自动路由 LoadSnapshotRouteSpec 特性: 新增自定义 @CommandRoute.appendTenantPath 特性: 支持命...

0
1
发表了资讯
07/14 08:42

Wow 2.3.2 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容 🎉 🎉 🎉 全面支持 OpenAPI 3 特性: 全面支持 OpenAPI 3 特性: 新增@CommandRoute.HeaderVariable 支持从请求头提取参数注入命令体 特性: 新增 HiddenVariableConverter 支持隐藏命令体中的路由变量 特性: 新增 CommandRoute.Method 支持自定义命...

1
4
发表了资讯
07/06 07:27

Wow 2.2.1 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容 🎉 🎉 🎉 特性: Wow 编译器(wow-compiler)支持检测聚合模型超类静态租户ID 特性: 新增 RecordEventFunctionErrorHandler 支持记录事件函数处理异常,以支持更友好的事件补偿 特性: AggregateVerifier 支持尽早检测状态聚合模型序列化问题 特性:...

1
2
发表了资讯
07/04 11:54

Wow 2.1.2 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容 🎉 🎉 🎉 提升无租户模式易用性 特性: Wow 编译器支持生成静态租户ID元数据 特性: 扩展函数 asAggregateId 支持静态租户ID检测 特性: 命令元数据 CommandMetadata 支持静态租户ID检测 特性: Wow应用元数据 WowMetadata 支持静态租户ID检测 架构图...

1
5
发表了资讯
07/03 08:48

Wow 2.1.0 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容 🎉 🎉 🎉 特性: 处理函数(@OnEvent/@OnCommand/@OnStateEvent)支持基于名称的服务注入 @OnCommand fun onCreateStaff( createStaff: CreateStaff, passwordEncoder: PasswordEncoder, @Name("usernamePre...

0
5
发表了资讯
06/21 08:00

Wow 2.0.1 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容 🎉 🎉 🎉 全面拥抱 Spring-Boot-3 特性: 支持 PrepareAutoConfiguration 依赖: 更新 me.ahoo.cosid:cosid-bom 版本v2.1.0 依赖: 更新 org.springframework.boot:spring-boot-dependencies 版本v3.1.0 依赖: 更新 spring-doc 版本v2.1.0 依赖: 更...

0
6
发表了资讯
06/14 07:55

Wow 1.18.5 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容 🎉 🎉 🎉 特性: 命令等待策略支持跨服务投影处理器完成信号 文档: wow-metadata.schema.json 适应性同步 特性: 支持 EventStoreStateAggregateRepository 依赖: MessageFunction 新增 NamedBoundedContext 元数据 重构: MonoCommandWaitNotifier...

0
4
发表了资讯
06/12 07:54

Wow 1.18.1 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容 🎉 🎉 🎉 支持 OnStateEvent,StateEvent=DomainEvent+ReadOnlyStateAggregate fun onStateEvent(orderCreated: OrderCreated, state: OrderState) { //... } fun onStateEvent(orderCreated: OrderCreated, state: R...

2
3
发表了资讯
06/09 08:08

Wow 1.16.3 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容 🎉 🎉 🎉 消息总线全面支持 LocalFirst模式 特性:支持 LocalFirstDomainEventBus 特性:支持 LocalFirstStateEventBus 架构图 事件源 可观测性 Spring WebFlux 集成 自动注册 命令 路由处理函数 (HandlerFunction) ,开发人员仅需编写领域模型,...

0
7
发表了资讯
06/08 09:05

Wow v1.16.0 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容(v1.16.0) 🎉 🎉 🎉 特性:支持 StateEventBus 特性:支持 TracingLocalStateEventBus/ TracingDistributedStateEventBus 特性:使用 StateEventBus 同步快照存储,以提升快照性能 特性:新增 LocalFirstMessageBus 以降低消费者处理网络延迟,...

1
5
发表了资讯
06/06 08:28

Wow v1.15.4 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容(v1.15.4) 🎉 🎉 🎉 特性:支持 TracingEventStore / TracingSnapshotRepository 特性:支持 ReadOnlyHeader 以防止非法写入 架构图 事件源 可观测性 Spring WebFlux 集成 自动注册 命令 路由处理函数(HandlerFunction) ,开发人员仅需编写领域...

0
9
发表了资讯
06/05 11:11

Wow v1.15.2 发布,让领域驱动设计变得触手可得

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架。 领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件源 更新内容(v1.15.2) 🎉 🎉 🎉 特性:支持 CommandProducerInstrumenter / EventProducerInstrumenter 特性:支持 RedisCommandBus / RedisDomainEventBus 重构:变更 Header 为可变的 特性:支持 RedisEventStore / RedisSnapshotRepository 特性:支持...

0
16
没有更多内容
加载失败,请刷新页面
点击加载更多
加载中
下一页
发表了博客
{{o.pubDate | formatDate}}

{{formatAllHtml(o.title)}}

{{parseInt(o.replyCount) | bigNumberTransform}}
{{parseInt(o.viewCount) | bigNumberTransform}}
没有更多内容
暂无内容
发表了问答
{{o.pubDate | formatDate}}

{{formatAllHtml(o.title)}}

{{parseInt(o.replyCount) | bigNumberTransform}}
{{parseInt(o.viewCount) | bigNumberTransform}}
没有更多内容
暂无内容
暂无内容
0 评论
21 收藏
分享
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部