MongoDB小课堂: 构建高可用股票仓位管理API服务(Express+Mongoose全栈实战)

【C语言】一文带你拿捏分支和循环语句(一万字详细讲解) if/switch语句、while/fo/do...while循环语句、goto语句详解 阅读详情

背景:服务架构设计原理


1 ) 核心目标
为股票交易场景构建安全的仓位管理API服务,通过中间层封装MongoDB操作,实现账户、股票代码、数量、价格等核心数据的全生命周期管理。解决直接暴露数据库导致的安全风险,提供标准化的CRUD接口。

2 ) 架构优势

客户端
路由层
控制器层
模型层
MongoDB数据库
  • 安全隔离:中间件架构防止直接数据库访问
  • 解耦设计:Model-Controller-Router分层(关注点分离)
  • 标准化交互:RESTful接口规范(POST/GET/PUT/DELETE)
  • 扩展性:可无缝集成身份验证、缓存等模块

要点

  • 生产环境必须通过服务层封装数据库操作,避免SQL注入、未授权访问等风险,同时保障数据一致性。

实现步骤与技术细节


1 ) 环境准备

工具作用安装命令
Node.js服务端运行时官网下载
MongoDB文档数据库docker run -p 27017:27017 mongo
PostmanAPI测试工具官网下载

2 ) 项目初始化

创建项目并安装依赖
mkdir position-service && cd position-service
npm init -y
npm install express mongoose body-parser
  • 关键依赖:
    • express:轻量级Web框架
    • mongoose:MongoDB ODM(对象文档映射)
    • body-parser:HTTP请求体解析中间件

3 ) 三层架构实现

3.1 模型层(Model)

// models/position.js
const mongoose = require('mongoose');
 
const positionSchema = new mongoose.Schema({
  account: { 
    type: String, 
    required: true,  // 强制字段验证
    minlength: 3     // 账户名最小长度
  },
  stock: { 
    type: String, 
    required: true,
    match: /^[A-Z]{1,5}$/  // 股票代码格式校验
  },
  quantity: { 
    type: Number, 
    required: true,
    min: [1, '数量不能小于1']  // 自定义错误提示
  },
  price: { 
    type: Number, 
    required: true,
    min: 0.01 
  }
});
 
module.exports = mongoose.model('Position', positionSchema);

3.2 控制器层(Controller)

// controllers/positionController.js
const Position = require('../models/position');
 
// 创建仓位(异步异常处理)
exports.createPosition = async (req, res) => {
  try {
    const newPosition = new Position(req.body);
    await newPosition.save();
    res.status(201).json({ 
      message: "仓位记录添加成功",
      id: newPosition._id  // 返回文档ID
    });
  } catch (err) {
    res.status(400).json({ 
      error: "数据校验失败",
      details: err.errors 
    });
  }
};
 
// 查询仓位(支持分页扩展)
exports.queryPositions = async (req, res) => {
  const { account, page=1, limit=10 } = req.query;
  try {
    const positions = await Position.find({ account })
      .skip((page-1)*limit)
      .limit(parseInt(limit));
    res.status(200).json(positions);
  } catch (err) {
    res.status(500).json({ error: "数据库查询异常" });
  }
};

3.3 路由层(Router)

// routes/positionRoutes.js
const router = require('express').Router();
const controller = require('../controllers/positionController');
 
router.post('/', controller.createPosition);       // POST /position
router.get('/', controller.queryPositions);         // GET /position?account=001 
router.put('/:id', controller.updatePosition);     // PUT /position/507f1f77bcf86cd7
router.delete('/:id', controller.deletePosition);  // DELETE /position/507f1f77bcf86cd7 
 
module.exports = router;
端点格式HTTP方法功能参数传递方式
/positionPOST创建仓位Body(JSON)
/position?account=001GET查询仓位Query String
/position/:idPUT更新仓位URL Params + Body
/position/:idDELETE删除仓位URL Params

4 ) 服务集成与启动

// app.js
const express = require('express');
const mongoose = require('mongoose');
const positionRoutes = require('./routes/positionRoutes');
 
const app = express();
app.use(express.json());  // 替代body-parser
 
// 生产环境连接配置(带认证)
mongoose.connect(process.env.DB_URI || 'mongodb://localhost:27017/demo', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  authSource: 'admin',
  user: process.env.DB_USER,
  pass: process.env.DB_PASS
});
 
// 全局错误处理中间件
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ code: 'SERVER_ERROR', message: '服务端异常' });
});
 
app.use('/position', positionRoutes);
app.listen(8888, () => console.log('服务运行中: http://localhost:8888'));

要点

  1. 使用环境变量(process.env)管理敏感信息
  2. Schema验证比应用层验证更接近数据源
  3. 统一的错误处理中间件可捕获所有未处理异常

案例:服务测试与验证


1 ) 测试用例(Postman示例)

操作请求示例预期响应
创建POST /position
Body: {"account":"001","stock":"AMZN","quantity":1,"price":1650}
201: {"message":"仓位记录添加成功", "id":"xxx"}
查询GET /position?account=001&page=1&limit=5200: [{account:"001", ...}]
更新PUT /position/507f1f77bcf86cd7
Body: {"quantity":2}
200: {"message":"仓位记录更新成功"}
删除DELETE /position/507f1f77bcf86cd7200: {"message":"仓位记录删除成功"}

2 ) 自动化测试脚本

// test/api.test.js (使用Jest + Supertest)
const request = require('supertest');
const app = require('../app');
 
describe('仓位管理API', () => {
  let positionId;
  
  test('创建仓位', async () => {
    const res = await request(app)
      .post('/position')
      .send({account: "TEST", stock: "TSLA", quantity: 10, price: 250});
    expect(res.statusCode).toEqual(201);
    positionId = res.body.id; // 保存ID用于后续操作
  });
 
  test('更新仓位', async () => {
    const res = await request(app)
      .put(`/position/${positionId}`)
      .send({ quantity: 15 });
    expect(res.statusCode).toEqual(200);
  });
});

要点

  1. Postman适合手动测试接口契约
  2. Jest+Supertest可实现自动化回归测试
  3. 测试覆盖率应包含异常路径(如非法参数)

部署方案


1 ) Docker容器化部署示例

FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8888
CMD ["node", "app.js"]

2 ) 性能压测

# 使用Artillery进行负载测试 
npm install -g artillery
artillery quick --count 50 -n 20 http://localhost:8888/position

3 )灾备方案

  • MongoDB副本集配置指南
  • 服务端日志持久化(ELK方案)

4 )前端集成示例

// React组件调用示例
const fetchPositions = async () => {
  const res = await fetch('/position?account=001');
  return res.json(); 
};

5 )限流保护

// 添加速率限制中间件
const rateLimit = require('express-rate-limit');
app.use('/position', rateLimit({ 
  windowMs: 15*60*1000, 
  max: 100 
}));

结论与关键知识点


1 ) 核心总结

  1. 安全架构:服务层封装使数据库远离客户端直接访问
  2. 高效开发:Mongoose ODM提供Schema验证、链式查询等高级功能
  3. 生产就绪:错误处理、环境变量、连接池优化保障稳定性

2 ) 生产级优化建议

  • 安全加固:
    // 启用HTTPS和CORS
    const https = require('https');
    const fs = require('fs');
    const server = https.createServer({
      key: fs.readFileSync('private.key'),
      cert: fs.readFileSync('certificate.crt')
    }, app);
    
  • 性能优化:
    // 连接池配置
    mongoose.connect(uri, {
      poolSize: 15, // 最大连接数
      socketTimeoutMS: 45000 
    });
    
  • 可观测性:
    • 添加日志中间件(如Winston)
    • 集成Prometheus监控指标

3 ) 扩展方向

模块实现方案业务价值
身份认证JWT + Passport.js防止未授权操作
缓存加速Redis缓存高频查询结果降低数据库负载
实时通知WebSocket推送仓位变更提升交易体验
文档自动化Swagger生成API文档降低对接成本

4 ) MongoDB vs 关系型数据库操作对比

在这里插入图片描述

-- SQL等效操作示例 
UPDATE positions 
SET quantity = 15 
WHERE id = '507f1f77bcf86cd7'; -- 需精确控制事务

要点

  1. MongoDB适合频繁变更的交易数据模型
  2. 关系型数据库在复杂事务中更有优势
  3. 混合架构(MongoDB+Redis)可兼顾性能与灵活性
手把手教你学Simulink——基于经典滤波器设计的场景:低通滤波器(LPF)的设计与频率响应仿真 滤波器是信号处理领域中非常重要的组件,用于去除不需要的频率成分或者提取有用的频率信息。低通滤波器(Low-Pass Filter, LPF)允许低于某个特定截止频率的信号通过,同时衰减高于该截止频率的信号。在本教程中,我们将学习如何使用设计一个简单的模拟低通滤波器,并对其频率响应进行仿真分析。本文介绍了如何使用设计一个简单的模拟低通滤波器,并通过仿真展示了其应用效果。通过这样的实践,您不仅能够加深对滤波器工作原理的理解,还能掌握利用Simulink进行滤波器设计与仿真的基本技能。 阅读详情

相关推荐

python入门:Anaconda和Jupyter notebook的安装与使用

一、安装和使用Anaconda 1、anaconda是什么? Anaconda在英文中是“巨蟒”的意思,与python的意思相近,它是python的包管理器和环境管理器。 2、为什么需要安装anaconda? 原因有以下几点: 附带一大批常用的数据科学包,方便立即开始处理数据 管理包 anaconda是在conda(一个包管理器和环境管理器)上发展来的;而conda可以很方便地对第三方的包进行安装、卸载和更新。 管理环境 conda可以为不同的项目建立不同的运行环境,避免不同的项目或包版本

PY洋洋 1万+

Mac下MySQL的配置和修改密码以及忘记密码后的重置密码

1 ) Mac下MySQL的配置和修改密码 2 ) 忘记并重置密码 启动MySQL服务,通过 $ps aux | grep mysql 判断是否启动该服务,若未启动,则到 系统偏好设置/MySQL面板 启动服务 软件默认会安装到:/usr/local/mysql 目录,进入这个目录下的bin目录:$cd /usr/local/mysql/bin 执行 $./mysql -u root -p 通过初始密码登录MySQL 通...

Wang的专栏 6259

盲盒小程序开发实战:概率算法、系统架构与合规风控全解析

抽奖类业务的核心是随机性与概率模型的工程化落地。从单品权重抽奖到动态保底机制,算法设计需要兼顾商业回报与用户体验;基于加密随机数服务端下发结果,可有效防止前端篡改与逆向分析。在系统层面,原子化库存扣减、幂等控制和审计日志构建了稳定可靠的抽奖服务,保障高并发下不超卖、不重复。盲盒小程序作为典型应用场景,还需深度融合微信支付v3对接与平台审核规范,尤其重视概率公示、未成年人保护和支付风控等合规红线。只有将算法、架构与合规三位一体,才能让产品顺利过审并长期运营。

weixin_31185473的博客 306

mysql数据库的一些简单的sql语句 内连接 - 表的关联查询

# 创建一个user表 create table users( id int primary key auto_increment, name varchar(20), dpt_id int ); # 向user表中插入数据 insert into users values (null,'刘备',1), (null,'关羽',2), (null,'赵

Wang的专栏 4264

别再手动更新Excel了!用Jira看板管理你的个人项目(附保姆级配置流程)

本文详细介绍了如何利用Jira看板替代Excel进行个人项目管理,提供从注册到配置的保姆级教程。通过极简看板模式、自动化规则和数据分析功能,帮助用户实现任务可视化、协作高效化和提醒自动化,大幅提升个人工作效率。特别适合需要管理复杂个人项目的用户。

weixin_42699679的博客 229

mac搭建ios自动化环境之WebDriverAgent配置

一、WebDriverAgent 1、简单介绍: WebDriverAgent是facebook为苹果公司开发的一款自动化测试工具,github上有下载资源;另外appium安装后也会自动安装自带的WebDriverAgent;可以用自带的,也可以从github下载并替换自带的; 2、不同appium版本自带WebDriverAgent默认路径不同 1)appium 1.10.1之前版本: npm方式安装: /usr/local/lib/node_modules/appium/node_modules/a

qq_30237715的博客 2765

数据库、数据库类型、RDBMS以及MySQL

什么是数据库 数据库 就是按一定的结构来组织、存储和管理数据的仓库 可以很方便的进行crud, 能提供多个用户共享、具有尽可能小的冗余度、与应用程序批次独立的数据集合。 其他持久储存缺点:文件操作(不灵活) 数据库类型 包括 : 关系型 和 非关系型 【关系型】 MySQL MariaDB PostgreSQL Microsoft SQL Server Oracle数据库 Sybase 【...

Wang的专栏 4039

Mediapipe入门——搭建姿态检测模型并实时输出人体关节点3d坐标(2024.1.4更新)

Mediapipe入门,利用mediapipe搭建人体整体检测模型,并输出右手21个关节点的坐标;mp_holistic.Holistic函数理解,mp_holistic.Holistic.process函数理解;mp.solutions.drawing_utils.draw_landmarks函数理解;Mediapipe实时姿态估计,3d骨架铰接图,matplotlib和Mediapipe绘图

kalakalabala的博客 6万+

Eggjs笔记:Eggjs集成ElasticSearch及CRUD操作

相关文档 https://www.elastic.co/guide/index.html https://www.elastic.co/guide/en/elasticsearch/client https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html https://www.elastic.co/guide/en/elasticsearch/client/javascrip

Wang的专栏 3530

ROM和RAM在单片机程序运行理解

ROM和RAM是电子设备中两种核心存储组件,主要区别在于:ROM用于长期存储系统程序、用户文件等固定数据,断电后数据不丢失,但写入速度较慢;RAM则用于临时存储运行中的程序和数据,读写速度快但断电后数据会清空。在单片机中,ROM存储程序代码和常量,RAM存储运行时的变量和数据。两者协同工作,ROM如同"永久档案库"保存必要信息,RAM则像"临时工作台"支持高速运算,共同确保设备正常运行。

qq_37999850的博客 1624

Python爬虫实战:如何抓取旅游论坛上的帖子、旅行攻略和评论内容

无论是知名的旅游网站,还是地方性的旅游讨论区,用户发布的旅行贴文、攻略和评论往往包含着大量的宝贵信息。本文将详细介绍如何使用Python编写一个爬虫,抓取旅游论坛上的帖子、旅行攻略和评论内容,涵盖从获取页面内容、解析数据到处理动态加载等各个方面的技术。从基本的请求和网页解析,到动态加载页面的处理,再到数据存储和反爬虫技巧,我们详细讲解了抓取旅游论坛数据的全过程。通过本文的介绍,你可以将所学的爬虫技术应用到其他类似的网站抓取任务中,为后续的数据分析、机器学习等任务提供丰富的数据源。在这种情况下,传统的。

2201_76125261的博客 1557

Redis: 集群高可用之故障转移和集群迁移

若要检查源和目标是否数据统一,还可选择阿里配套工具RedisFullCheck。3.4 使用 RedisFullCheck 工具检查。下载官方编译好的工具包,直接解压后就能使用。故障转移,包括自动故障转移和手动故障转移。运行之后,就给一个反馈结果,如果是。1.2 原集群与目标集群结构不一致。1.1 原集群与目标集群结构一致。2 ) 手动故障转移。

Wang的专栏 2918

Python爬虫实战:基于最新技术栈的政府招标采购数据抓取与分析

对于企业、研究人员和数据分析师来说,能够高效地获取这些数据意味着可以获得宝贵的商业洞察和市场先机。随着反爬技术的不断升级和网站结构的日益复杂,传统的爬虫方法已经难以满足需求。我们将采用Selenium、Playwright等现代浏览器自动化工具,结合Scrapy框架和异步请求库,构建一个能够应对各种反爬措施的强大爬虫系统。Playwright是微软开发的浏览器自动化工具,支持Chromium、WebKit和Firefox,比Selenium更快速、更稳定。

2201_76125261的博客 1313

Python笔记:基于Django框架的数据库设计

概述 需要根据《项目建议书》、《需求说明书》、界面原型、各种标准规范对数据库进行设计, 我们目前先参考这一设计图 结构设计 1 ) 找实体 实体是实体-关系模型的基本对象, 是现实世界中各种事物的抽象。 凡是可以相互区 开并可以被识 的事、物、概念等对象均可认为是实体。 基本的实体列表如下: 会员 类别 商品 订单 订单详情 收货地址 商品评论 商品图片 友情链接 站内公告 … ...

Wang的专栏 2772

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Elastic Stack梳理:集群搭建指南之高可用架构与实战部署

本文介绍了Elasticsearch分布式架构和Cerebro监控工具的部署策略。主要内容包括: ES集群角色划分(主节点、数据节点、协调节点)及功能说明 Cerebro监控工具的独立部署方法和访问方式 集群拓扑规划示例,包含节点IP分配和架构拓扑图 各类型节点的配置原则和数量计算公式 高可用主节点配置要点及示例配置 生产环境优化建议,包括分片规划、硬件配置和安全措施 文章提供了完整的集群部署方案,涵盖从基础概念到具体实施的各个环节,适用于不同规模的ES集群建设。

Wang的专栏 2545

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Redis: 集群环境搭建,集群状态检查,分析主从日志,查看集群信息

当从节点获得足够多的选票时,它就会成为新的主节点,并增加自己的configEpoch来更新槽位配置。在Redis集群中,纪元的更新通常是由节点间的通信和状态变更触发的。例如,当某个节点接收到来自其他节点的状态变更通知时,它会比较通知中的纪元与自己的纪元。如果通知中的纪元更大,则更新自己的纪元。确保集群状态的一致性:通过递增的纪元,集群中的节点可以确保它们对集群状态的认知是一致的。通过递增的纪元版本号,集群中的节点可以确保它们对集群状态的认知是一致的,并解决可能出现的配置冲突问题。4 )纪元的更新机制。

Wang的专栏 2466

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

MySQL: 数据库性能的决定性因素之从双十一大促高并发场景看系统瓶颈与优化路径

电商大促期间,数据库面临高并发写入、连接数暴增、慢查询积压等核心挑战。本文分析了锁竞争、主从延迟等关键性能瓶颈,并提出多种优化方案:1)使用乐观锁通过版本号控制库存超卖;2)CAS机制实现无锁并发;3)分布式锁协调多节点操作。这些方案在保证数据一致性的同时提升吞吐量,适用于库存扣减、订单创建等典型场景,有效解决数据库扩展难题。

Wang的专栏 2426

Redis: Sentinel哨兵监控架构及环境搭建

在主从模式下,我们通过从节点只读模式提高了系统的并发能力并发不断增加,只需要扩展从节点即可,只要主从服务器之间,网络连接正常主服务器就会将写入自己的数据同步更新给从服务器,从而保证主从服务器的数据相同在这种架构下,它仍然是有一些缺点的,比如说它的可靠性保证不是很好,因为主从模式下,主节点故障了便无法提供写入的服务现在,我们通过哨兵来解决这个问题然后,主节点其实写的压力也是并没有被释放的包括主从之间的数据是相同的,它还有数据冗余一个问题后面集群也会解决这个问题。

Wang的专栏 2181

MongoDB小课堂: 高级查询操作符与游标管理综合指南之深度整合逻辑操作符、字段处理、数组查询与游标控制的最佳实践

MongoDB查询操作符与游标管理摘要 本文整合了MongoDB常用查询操作符和游标管理的关键知识点: 比较操作符: $in和$nin用于多值匹配,注意$nin会包含字段缺失文档 结合$exists可处理字段缺失问题 逻辑操作符: $and可简写为逗号分隔条件 $or可用$in优化等值查询性能 $not和$nor需谨慎处理字段缺失 字段操作符: $exists检查字段存在性 $type支持按BSON类型筛选 数组操作符: $all要求包含所有指定元素 $elemMatch匹配满足条件的数组元素 正则表达式:

Wang的专栏 2145

Redis: 集群测试和集群原理

Redis Cluster 没有单机那种 16个数据库 (0 - 15) 数据库的概念了,就是我们已经看不到数据库了。而是分成了 16384 个 slots (槽位) ,每个节点负责其中一部分槽位,槽位的信息存储于每个节点中。2 ) 16384 个 slots (槽位)那我们客户端这边是怎么来操作集群的呢?1 ) SET/GET 命令。2 ) 开启从节点只读模式。

Wang的专栏 2102

Eggjs笔记:详解Mongoose的聚合管道以及populate实现关联查询

基于mongodb的聚合管道 此处忽略之前mongodb在eggjs中需要配置的步骤,前文已有说明,现在开始在controller中调用(应该封装到service中的,仅作为示例) const result = await this.app.mongo.aggregate('order', { pipeline: [ { $lookup: {...

Wang的专栏 2096

MySQL: 数据库监控核心要素与实施策略

数据库监控是确保系统稳定的关键,涵盖服务可用性、性能、主从复制和资源使用等方面。核心监控包括:通过真实连接和查询验证数据库可用性;跟踪QPS、TPS和并发线程数等性能指标;监控主从复制的链路状态和延迟;以及关注磁盘空间等服务器资源。实现方案包括网络连接验证、读写测试和连接数阈值监控。性能监控需持续记录数据趋势,并采用精准方法检测阻塞事务和复制延迟。全面的数据库监控能有效预防故障,保障系统稳定运行。

Wang的专栏 2096

MySQL: 索引优化策略详解:核心原则、高级应用与维护实践

本文介绍了数据库索引优化的核心策略。第一部分重点讲解高效索引设计原则:禁止在索引列使用表达式或函数;合理使用前缀索引以平衡选择性和存储空间;设计联合索引时应优先考虑高频查询、高选择性和小宽度列;以及利用覆盖索引减少回表查询。第二部分探讨索引的高级应用,特别强调通过合理设计索引优化排序操作。文章指出索引列顺序需与ORDER BY完全一致,并分析了InnoDB与MyISAM存储引擎在排序支持上的差异。通过实际SQL示例展示了索引优化前后的性能差异,为数据库性能调优提供了实用指导。

Wang的专栏 2061

屏幕不止一种:OLED、LCD1602字符屏、TFT/IPS图形屏和串口屏怎么用,这与TTY和PTY又有什么关系

要图像、要曲线、要一块比现在更大的画面,面前的屏就不止一种了。OLED、LCD1602字符屏、TFT/IPS图形屏和串口屏怎么用,又该按什么来挑?这与TTY和PTY又有什么关系?

Lxx_Zw的博客 318

5个陷阱和解决方案:MongoDB源码中自动化测试平台的数

在现代软件工程实践中,自动化测试平台扮演着至关重要的角色,它确保了系统的稳定性和迭代的可靠性。然而,随着业务数据量的快速增长以及并发写入需求的不断上升,基于MongoDB构建的自动化测试平台常常面临性能瓶颈和数据一致性问题。本文将围绕MongoDB源码中一个关键模块——,通过一行一行代码的解读,揭示其设计原理、性能调优点及常见陷阱,适合希望深入理解数据库实现机制的高级工程师。

wuchangjian的专栏 175

用Ai8051帮我写一个FX3UPLC 程序

用Ai8051帮我写一个FX3UPLC 程序AI这个需求我得先跟您确认清楚,因为"用Ai8051U写一个FX3U PLC程序"这个说法本身存在歧义,我不能凭猜测直接给您出一套代码。

czhaii的专栏 303
上一篇: MongoDB小课堂: 深度掌握$lookup聚合——从基础语法到高级关联查询实战指南
下一篇: MongoDB小课堂: 数据模型设计从基础到实战——文档结构、关系表达与树形建模深度指南
Wang's Blog
博客等级 码龄12年 7438粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值