IT技术家园 - 工具
type: channel
link: https://www.itbunan.xyz/category/gj/
description: 不知道归到哪一类
items: 从零搭建一个手机号过滤平台：PBlack 架构全解析
items: 从零搭建一个短信平台：LESMS 架构全解析
items: 手机号黑名单库查询逻辑与性能优化分享
items: 短信通道管理平台之多层架构与Worker异步处理设计分享
items: CVOICE语音质检系统：一个看板掌控全局，管理看板深度解析
items: 基于Django的录音管理系统的开发总结
items: 爆火的轻量级AI证件照工具HivisionIDPhotos部署过程
items: 支付网关DaxPay部署测试改造过程
items: 新客户端IP一键过白功能开发与配置
items: 扫码点餐系统管理后台界面

从零搭建一个手机号过滤平台：PBlack 架构全解析
type: item
date: 2026-03-07T09:11:00+00:00
description: 今天聊聊 PBlack——一个开源的手机号黑名单/白名单检测平台。我会从架构设计的角度，拆解它是如何解决这些痛点的，以及为什么选择 Vue + Django + Go 这样的技术组合。为什么需要手机号过滤？先说说背景。在金融风控、电商防刷、社交平台注册这些场景里，手机号是最基础的身份标识。但问题来了：骚扰电话营销：用户被各种推广电话轰炸，体验极差羊毛党批量注册：用虚拟号、接码平台批量薅羊毛欺诈风险：黑名单号码反复作案，平台损失巨大传统的解决方案要么简单粗暴（直接拒接所有陌生号），要么成本太高（每次都要调用第三方接口）。PBlack 的设计目标就是：既要快，又要准，还要省钱。整体架构：三层分离PBlack 采用前后端分离的微服务架构，核心分为三层：┌─────────────────────────────────────────────────────────┐ │ 前端层 (pfront) │ │ Vue 3 + TypeScript + Vite │ │ 管理界面、API 密钥管理、消费统计看板 │ └─────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ API 服务层 (papi) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ phone-filter │ │ teddy-api │ │ pfront-api │ │ │ │ -api (Go) │ │ -proxy (Go) │ │ (Go) │ │ │ │ 黑名单检测 │ │ 上游代理 │ │ 认证/消息 │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ 数据与管理后台层 │ │ Django + PostgreSQL + Redis │ │ 用户管理、号码库、访问记录、缓存加速 │ └─────────────────────────────────────────────────────────┘这个分层不是拍脑袋决定的。每一层都有自己的职责，而且可以独立部署、独立扩展。技术选型：为什么这样组合？前端：Vue 3 + Vite选择 Vue 3 而不是 React，主要是考虑开发效率和团队熟悉度。Vite 的冷启动速度比 Webpack 快一个数量级，本地开发体验很好。TypeScript 是必须的——手机号过滤涉及大量的 API 接口对接，类型安全能避免很多低级错误。管理后台：DjangoDjango 的 admin 界面是开箱即用的。用户管理、API 密钥管理、黑白名单维护这些功能，用 Django 的 ModelAdmin 几行代码就能搞定。如果用 Go 写后台，光 CRUD 接口就要写一堆。Django 的 ORM 和 admin 在这种场景下是降维打击。核心检测服务：Go这是整个系统的性能瓶颈所在。手机号检测是高频操作，QPS 可能达到几千甚至上万。Go 的 goroutine + channel 模型非常适合这种高并发、低延迟的场景。实测下来，单机可以轻松支撑 10k+ QPS。// 核心检测逻辑：Redis Set 的 O(1) 查询 func (s *BlacklistService) CheckSingleNumber(phone string) (bool, error) { isBlacklisted, err := database.IsPhoneInBlacklistSet(phone) if err != nil { return false, err } s.updateStats(isBlacklisted) return isBlacklisted, nil }数据流转：一次检测请求的全流程来看看一个黑名单检测请求是怎么处理的：客户端 → phone-filter-api → 签名验证 → 用户鉴权 → Redis 查询 ↓ 客户端 ← 返回结果 ← 组装响应 ← 命中判定 ← 黑名单 Set关键设计点：Redis Set 存储：黑名单和白名单分别用 Redis 的 Set 数据结构存储，SISMEMBER 命令是 O(1) 复杂度，百万级号码也能毫秒…

从零搭建一个短信平台：LESMS 架构全解析
type: item
date: 2026-03-02T06:12:00+00:00
description: 短信服务看似简单，但真要自己搭一个能支撑业务运转的平台，坑比想象中多得多。去年有个朋友找我吐槽：公司每个月短信费用好几万，想自建平台省点钱。我反问了他三个问题——高并发怎么扛？通道故障怎么切？账单对不上怎么办？ 他沉默了。这就是短信平台的真相：发一条短信容易，发一亿条还能稳定、安全、可追踪，完全是另一回事。今天聊聊我自己写的 LESMS这个项目，看看一个轻量级企业短信平台是怎么从 0 到 1 搭建起来的。一、为什么要自己搭短信平台？先泼点冷水——大部分公司不需要自建短信平台。直接接阿里云、腾讯云，API 调一下就能用，省心省力。但以下几种情况，自建就有意义了：成本敏感：月发送量过百万，第三方平台的单价和附加费会吃掉不少利润数据合规：金融、医疗行业，用户手机号不能外流到第三方功能定制：需要特殊的签名审核流程、定时发送策略、精细化的通道调度技术储备：团队有能力维护，且业务长期依赖短信触达LESMS 的定位很明确：中小型企业的自建方案，不求大而全，但求核心链路稳、二次开发易。二、三模块架构设计整个系统拆成三大块，每块只干一件事：1. Django 管理后台：业务的"大脑"Django 在这里扮演两个角色：一是客户中心 API。用户注册、登录、余额查询、发送记录查看，这些面向客户的接口都由 Django 提供。用 Django REST Framework（DRF）写起来很快，自带序列化、权限控制、限流。二是运营管理后台。基于 Django Admin 改造的管理界面，运营人员可以在里面审核签名、配置通道、查看统计报表。SimpleUI 美化了一下，至少不像原生 Admin 那么丑。关键模块包括：用户管理：实名认证、企业认证、余额与计费消息管理：模板审核、签名报备、上下行记录通道管理：多运营商通道配置、黑名单管理充值管理：套餐、订单、卡密核销2. Vue 3 前端：用户的"门面"前端用的是 Vue 3 + TypeScript + Element Plus，基于 Vben Admin 框架二次开发。为什么不用 Django 自带的模板？因为现代前端工程化已经成熟了，Vue 的组件复用、状态管理、构建优化都比传统后端渲染强太多。前端主要承载：客户自助服务：发送短信、查看记录、管理通讯录可视化数据：发送成功率、消费趋势、通道质量开发者工具：API 密钥管理、SDK 下载、调试控制台3. Go API 服务：性能的"发动机"这是整个系统的性能担当，用 Go + Gin 框架实现。短信发送有几个特点：高并发、低延迟、重可靠。Django 是同步阻塞模型，处理这种场景比较吃力；Go 的 goroutine + channel 天然适合高并发网络 IO。Go 服务负责的核心功能：短信发送接口：接收请求、校验签名、写入队列Worker 调度：从 Redis 队列取任务，分发到不同运营商通道状态回执：接收运营商的送达报告，更新数据库上行处理：处理用户回复的短信（MO）三、技术选型背后的思考有人可能会问：为什么搞这么复杂，用一种技术栈不行吗？当然行，但会有代价。模块选型理由管理后台Django快速开发、生态成熟、Admin 开箱即用核心 APIGo高并发性能、部署简单、资源占用低前端Vue 3组件化、TypeScript 支持好、团队熟悉数据库PostgreSQLACID 保障、JSON 字段支持、运维友好队列/缓存Redis原子操作丰富、持久化可选、生态完善一句话总结：让合适的工具做合适的事。Django 适合业务逻辑复杂、变更频繁的场景；Go 适合性能敏感、高并发的场景。两者通过 REST API + Redis 队列协作，既保留了各自的优势，又避免了过度耦合。四、一条短信的完整旅程光讲架构有点抽象，我们跟踪一条短信从用户点击"发送"到手机收到的全过程：第一步：前端提交用户在 Vue 界面填写手机号、选择模板、点击发送。前端组装请求体，带上时间戳、nonce、签名，调用 /api/v1/sms/send。第二步：Go 服务接入Go 服务收到请求，依次执行：中间件链：CORS → 日志 → 签名校验 → 限流检查参数校验：手机号格式、模板是否存在、余额是否充足写入队列：将任务序列化后推入 Redis 队列第三步：Worker 调度Worker 进程从队列取出任务：解析手机号前 7 位，识别归属运营商（移动/联通/电信）查询用户的通道配置策略选择最优通道，HTTP 调用运营商网关第四步：运营商处理运营商网关返回提交结果（成功/失败），Worker 记录提交状态。真正的送达是异步的——运营商会在短信送达后推送状态报告。第五步：状态回执运营商回调 Go 服务的 /callback/status 接口，携带手机号、状态、时间戳。Go 服务更新数据库中的发送明…

手机号黑名单库查询逻辑与性能优化分享
type: item
date: 2026-02-27T08:17:00+00:00
description: 在高并发场景下，如何实现毫秒级的手机号黑名单校验？本文将深入剖析一个生产级黑名单系统的核心架构与技术实现。一、总体介绍在短信通道、语音呼叫、风控审核等业务场景中，手机号黑名单校验是一项高频且关键的能力。想象一下，当用户发起呼叫或发送短信时，系统需要在毫秒级时间内判断目标号码是否在黑名单中——这直接关系到业务合规性和用户体验。本文介绍的手机号黑名单库是一个面向运营/风控场景的完整解决方案，具备以下核心特性：双通道架构：Django 管理后台 + Go 高性能 API 服务毫秒级响应：依托 Redis 缓存实现单次查询 < 5ms百万级数据支持：轻松支撑千万级黑名单数据量灵活接入方式：支持单号查询、批量查询（最多 500 个）二、技术要点1. Redis Set 数据结构：空间换时间的极致实践是什么：使用 Redis 的 Set（集合）数据结构存储黑名单手机号，而非传统的 Hash 或 String。为什么这么做：Set 的 SISMEMBER 命令时间复杂度为 O(1)，无论数据量多大，查询性能恒定内存占用优化：存储 1000 万个 11 位手机号仅需约 400MB 内存天然去重：Set 自动处理重复号码，简化业务逻辑核心价值：单机 Redis 可支撑 10 万+ QPS 的查询压力，满足绝大多数业务场景。2. 冷热分离架构：PostgreSQL + Redis 双层存储是什么：PostgreSQL 作为持久化存储（冷数据），Redis 作为查询缓存（热数据）。为什么这么做：数据安全：PostgreSQL 保证数据不丢失，支持事务和备份查询性能：Redis 避免频繁访问数据库，减轻 DB 压力水平扩展：Redis 可部署集群模式，支持数据分片核心价值：兼顾数据可靠性和查询性能，实现"写入慢、读取快"的最优解。3. 原子切换机制：零停机数据更新是什么：使用临时 Set + RENAME 命令实现黑名单数据的无缝切换。为什么这么做：避免更新过程中的数据不一致问题切换操作是原子性的，微秒级完成业务层无感知，零停机时间核心价值：支持百万级数据的全量更新，而不影响线上查询服务。4. Pipeline 批量查询：网络延迟优化是什么：使用 Redis Pipeline 技术批量发送查询命令，减少网络往返次数。为什么这么做：单次网络 RTT 约 1-5ms，批量查询可将 500 个号码的查询时间从 2500ms 降至 10ms减少 Redis 服务器处理开销核心价值：批量查询接口支持 500 个号码一次性校验，响应时间 < 50ms。5. 签名验证机制：API 安全防护是什么：基于 MD5 的参数签名验证，防止接口被恶意调用。为什么这么做：防止请求被篡改（如修改查询号码）防止重放攻击（时间戳有效期 5 分钟）身份认证（AppId + AppSecret 模式）核心价值：确保只有授权用户才能访问黑名单查询服务。三、核心代码片段1. Redis 批量查询实现// BatchIsPhoneInBlacklistSet 使用 Pipeline 批量查询号码是否在黑名单中 func BatchIsPhoneInBlacklistSet(phones []string) (map[string]bool, error) { if len(phones) == 0 { return make(map[string]bool), nil } pipe := RedisClient.Pipeline() cmds := make(map[string]*redis.BoolCmd) // 批量发送 SISMEMBER 命令 for _, phone := range phones { cmds[phone] = pipe.SIsMember(ctx, BlacklistSetKey, phone) } // 执行所有命令（一次网络往返） _, err := pipe.Exec(ctx) if err != nil { return nil, err } // 处理结果 results := make(map[string]bool) for phone, cmd := range cmds { isMember, err := cmd.Result() if err != nil { // 单个查询出错，默认不在黑名单 results[phone] = false } else { results[phone] = isMember } } return results, nil }核心逻辑解读：使用 Pipeline 将多个 SISMEMBER 命令打包发送所有查询共享一次网络往返，大幅降低延迟结果逐个解析，单个失败不影响整体2. 原子切换实现// Atomi…

短信通道管理平台之多层架构与Worker异步处理设计分享
type: item
date: 2026-02-27T07:29:03+00:00
description: 今天来聊聊我们在构建企业级短信平台时的一些架构设计心得。短信服务看似简单，但要在高并发场景下保证稳定性、可观测性和可扩展性，背后的技术选型与架构设计才是关键。一、总体介绍1.1 解决的问题在短信业务中，我们面临几个核心挑战：高并发写入：营销活动期间，短时间内可能有数万条短信发送请求涌入实时性与可靠性的平衡：用户希望短信立即发出，但下游通道往往有速率限制多维度统计：需要实时统计发送量、成功率、计费信息风控合规：黑名单过滤、敏感词检测必须在发送前完成1.2 在平台中的位置本文介绍的架构设计是整个短信平台的"中枢神经"，位于 API 接入层与下游通道之间，承担着请求调度、异步处理、数据持久化的核心职责。1.3 核心价值通过"分层架构 + Worker 异步处理"的设计，我们实现了：解耦：API 层只负责接收请求，具体处理交给 Worker削峰：利用队列缓冲突发流量可扩展：Worker 可以水平扩容可观测：每个组件都有独立的日志输出二、技术要点2.1 三层架构设计我们的平台采用经典的三层架构：┌─────────────────────────────────────────────────────────────┐ │ 前端 (Vue 3) │ │ customer-web - Vben Admin 框架 │ └───────────────────────────┬─────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────┐ │ Nginx 反向代理 │ └───────────────┬───────────────────────────┬─────────────────┘ │ │ ┌───────────────▼───────────┐ ┌───────────▼─────────────────┐ │ Django 管理后台 │ │ Go API 服务 │ │ (ladmin) │ │ (lsms-api) │ │ - 用户管理 │ │ - 短信发送 API │ │ - 模板/签名审核 │ │ - 调度器 │ │ - 充值管理 │ │ - Worker 集群 │ │ - 统计报表 │ │ - 计费 Worker │ │ │ │ - 统计 Worker │ │ │ │ - 黑名单 Worker │ └───────────────┬───────────┘ └───────────┬─────────────────┘ │ │ ┌───────────────▼───────────────────────────▼─────────────────┐ │ PostgreSQL + Redis │ │ 数据持久化 + 缓存/队列 │ └─────────────────────────────────────────────────────────────┘技术选型考量：Vue 3 + Vben Admin：现代化前端生态，组件丰富，适合构建复杂的运营后台Django：成熟的企业级后台框架，自带 Admin 界面，适合快速开发管理功能Go API 服务：高并发、低延迟，适合短信发送这类 IO 密集型场景PostgreSQL：ACID 事务、JSONB 支持，适合存储复杂的业务数据Redis：高性能缓存与队列，支撑高并发与解耦2.2 Worker 异步处理机制Worker 是我们架构的核心创新点。当 API 接收到发送请求后，不会立即处理，而是：写入队列：将任务推入 Redis 队列记录日志：在 PostgreSQL 中创建发送记录异步处理：多个 Worker 从队列中拉取任务并行处理flowchart TD Start(["接收发送请求"]) --> Validate["校验签名/限流/鉴权"] Validate --> Enqueue["写入发送队列(Redis)"] Enqueue --> Record["记录发送记录(PostgreSQL)"] Record --> Dispatch["调度器分发任务"] Dispatch --> Billing["计费 Worker 处理"] Dispatch --> Stats["统计 Worker 处理"] Dispatch --> Blacklist["黑名单过滤 Worker 处理"] Billing --> Update["更新计费/余额"] Stats --> UpdateStats["更新统计指标"] Blacklist --> FilterOK{"命中黑名单?"} FilterOK --> |是| Drop["丢弃/标记失败"…

CVOICE语音质检系统：一个看板掌控全局，管理看板深度解析
type: item
date: 2026-02-26T08:26:11+00:00
description: 总体介绍在语音质检系统中，运营管理者面临的最大痛点之一就是信息分散：用户数据、录音状态、敏感词告警、财务消费……分布在不同页面，想要全面了解系统运行状况，需要反复切换、手动汇总。CVOICE语音质检系统的管理看板（Dashboard）正是为解决这一问题而生。它将系统中最核心的运营指标——用户数量、节点状态、录音处理进度、告警消息、财务概览、质检规则排行——全部汇聚在一个页面上，配合可视化图表和实时统计，让管理者打开浏览器就能"一眼看穿"系统全貌。无论是日常巡检还是异常排查，看板都能成为你的"数字驾驶舱"。技术要点1. 后端架构：自定义 Django AdminSiteCVOICE的管理看板并非使用第三方BI工具，而是基于Django Admin框架进行了深度定制。通过继承 AdminSite 类，注册自定义URL，将看板页面无缝嵌入到后台管理系统中：class CustomAdminSite(AdminSite): site_header = '语音质检平台' def get_urls(self): urls = super().get_urls() custom_urls = [ path('dashboard/', self.admin_view(self.dashboard_view), name='dashboard'), path('realtime-stats/', self.admin_view(self.realtime_stats_view), name='realtime_stats'), ] return custom_urls + urls这种方式的好处是：看板天然继承了Django Admin的认证和权限体系，只有经过身份验证的管理员才能访问，无需额外实现鉴权逻辑。2. 多维度数据聚合看板页面在一次请求中完成了超过30项指标的实时计算，覆盖6大维度：维度核心指标数据来源用户管理总用户数、活跃/禁用/欠费分布CUser模型节点状态在线/离线、审核状态分布CUserAgent模型录音处理总量、今日新增、检测状态分布PhoneRecording模型语音转写转写总量、审核状态、质检结果SpeechToText模型告警消息总量、待处理数AlertMessage模型财务统计总余额、累计消费、今日消费ConsumptionRecord模型所有查询均使用Django ORM的 count()、aggregate(Sum()) 和 filter() 链式调用，保持了代码的简洁性和可维护性。3. 可视化图表：Chart.js驱动看板中集成了两类动态图表，均由 Chart.js 4.x 渲染：近7天录音趋势折线图：展示系统整体的录音采集量走势，帮助发现异常波动。节点维度录音趋势：取录音量TOP5的节点，按天展示各自的录音增长曲线，便于定位"高产"或"沉默"节点。图表数据在后端通过循环计算7天内每天的录音数量，序列化为JSON后传递给前端模板：for i in range(6, -1, -1): day = today - timedelta(days=i) day_start = timezone.make_aware(timezone.datetime.combine(day, timezone.datetime.min.time())) day_end = day_start + timedelta(days=1) count = PhoneRecording.objects.filter( created_at__gte=day_start, created_at__lt=day_end ).count() daily_recordings.append(count)4. 质检规则排行榜看板底部设计了质检规则排行榜，从两个角度排名：按录音条数排序：哪条规则命中的录音最多？按总音频时长排序：哪条规则覆盖的通话总时长最长？这为规则优化和资源分配提供了直观的数据支撑。核心代码/配置片段看板的前端采用 Bootstrap 5 构建响应式布局，使用CSS渐变变量统一视觉风格：:root { --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); --success-gradient: linear-gradient(135deg, #11998e 0%, #38ef7d 100%); --warning-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); }每个指标卡片通过统一的 stat-card 组件展示，支持趋势标识（如"今日+N"）： {{ total_record…

基于Django的录音管理系统的开发总结
type: item
date: 2024-10-24T12:00:00+00:00
description: 前言安卓手机默认打开了通话录音功能，几年下来积攒了上千条录音，一直懒得清理。最近写了一个管理系统，将所有录音文件导入。进行可视化分析，给自己几年打的所有电话生成一份报告。更直观的展示自己的通讯情况。{card-default label="统计" width="80%"}{/card-default}开发过程录音文件的管理通过django框架开发，主要功能点有通讯录管理、录音文件管理、录音文件转文字管理。转文字通过调用腾讯api完成，将结果保存到数据库，便于查询。可视化模块通过grafana直接读取mysql数据实现。模型类的设计模型类包括三种，Contact类、CallRecord类和RecordResult类。Contact类存储通讯录信息，包含名称和号码等class Contact(models.Model): number = models.CharField(max_length=15,verbose_name='电话号码') # 电话号码 name = models.CharField(blank=True,null=True,max_length=100,verbose_name='联系人') # 联系人姓名 # 新增的类型字段 TYPE_CHOICES = [ ('family', '亲朋'), ('work', '工作'), ('promotion', '推广'), ('taxi', '滴滴'), ('service', '客服'), ('delivery', '快递'), ] contact_type = models.CharField( max_length=10, choices=TYPE_CHOICES, verbose_name='类型', default='promotion', # 默认值为'亲朋' ) def __str__(self): return self.number class Meta: verbose_name = '通讯录' verbose_name_plural = '通讯录'CallRecord类用于存储音频文件、状态、音频转文字的任务信息等class CallRecord(models.Model): phone_number = models.ForeignKey(Contact, related_name='call_records', on_delete=models.CASCADE) # 电话号码外键 call_time = models.DateTimeField(verbose_name='时间') # 通话时间 recording_file = models.CharField(max_length=255, blank=True, null=True, verbose_name='文件名') # 录音文件名 notes = models.TextField(blank=True, null=True, verbose_name='备注') # 备注 task_id = models.CharField(max_length=255, blank=True, null=True, verbose_name='任务id') # 任务ID，可为空 # 状态字段的选择 STATUS_CHOICES = [ ('未处理', '未处理'), # Unprocessed ('处理中', '处理中'), # Processing ('已完成', '已完成'), # Completed ] status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='未处理', verbose_name='状态') # 状态，默认值为 '未处理' def __str__(self): return f"{self.phone_number.number} - {self.call_time}" # 返回通话记录的字符串表示 class Meta: verbose_name = '通话录音' # 该模型的单数名称 verbose_name_plural = '通话录音' # 该模型的复数名称RecordResult用于管理存储音频转文字的结果等信息class RecordResult(models.Model): call_record = models.OneToOneField(CallRecord, related_name='record_result', on_delete=models.CASCADE) # 与 CallRecord 的一对一关系 # 录音时长，单位为秒 duration = …

爆火的轻量级AI证件照工具HivisionIDPhotos部署过程
type: item
date: 2024-09-27T02:52:00+00:00
description: 前言HivisionIDPhotos是一款轻量级的AI证件照制作工具，它利用先进的图像处理技术和机器学习算法，简化了证件照的制作流程，确保生成的照片既符合官方证件的尺寸要求，又保持了高质量。无论是申请护照、驾照还是学生证，我们都可以用它来快速生成符合标准的证件照。{card-default label="制作界面" width="90%"}{/card-default}项目地址： HivisionIDPhotos部署采用docker启动，docker的安装参考以前的教程。部署很简单直接docker启动即可。基本环境docker和docker-compose一键安装脚本项目启动docker-compose up 项目文件:version: '3.8' services: hivision_idphotos: build: context: . dockerfile: Dockerfile image: linzeyi/hivision_idphotos command: python3 -u app.py --host 0.0.0.0 --port 7860 ports: - '3000:7860' hivision_idphotos_api: build: context: . dockerfile: Dockerfile image: linzeyi/hivision_idphotos command: python3 deploy_api.py ports: - '8080:8080'测试访问：http://ip:7860上传一张普通照片，然后即可制作。使用简单，制作质量也可以满足要求。{card-default label="制作效果" width="90%"}{/card-default}

支付网关DaxPay部署测试改造过程
type: item
date: 2024-09-02T09:24:00+00:00
description: 前言DaxPay单商户是一套开源支付网关系统，已经对接支付宝、微信支付相关的接口。可以独立部署，提供接口供业务系统进行调用，不对原有系统产生影响， 适用于小型项目或简单收单的场景。本文记录部署测试记录。{card-default label="收款页面" width="90%"}{/card-default}核心技术栈JDK,1.8+，11版本可以正常使用，但17+版本暂不支持SpingBoot, 2.7xRedis, 5.x版本以上Mysql,5.7.X以上Vue,前端框架3.x项目部署过程数据库mysql,redis的部署过程略过。可以查阅一下往期的文章。本文主要记录项目代码部署的相关过程。所有项目代码的地址： 【支付源码】开源免费支付系统DaxPay源码数据库创建一个daxpay的数据实例。同时在后端项目中_config/sql目录下找到dax-pay.sql数据库脚本文件，导入daxpay数据库。# 建库 mysql -uroot -pmariadb@xxx -h 127.0.0.1 CREATE DATABASE `daxpay` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; create user 'dpuser'@'%' IDENTIFIED BY 'dpuserxxx'; grant all privileges on daxpay.* to 'dpuser'@'%'; flush privileges; # 导入demo数据 mysql -udpuser -pdpuserxxx -h 127.0.0.1 daxpay < ./_config/mysql/dax-pay.sqljava环境利用java和maven打包后端代码，在打包之前修改application.yml内的数据库连接信息。# java和maven的安装 yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel wget https://downloads.apache.org/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz tar xvf apache-maven-3.8.8-bin.tar.gz mv apache-maven-3.8.8 /usr/local/maven # maven配置国内源 vim ~/.m2/settings.xml 内容见下面... # maven版本验证 java -version mvn -version # 项目打包 mvn -B clean package -Dmaven.test.skip=true -Dmaven.javadoc.skip=true -Dautoconfig.skipmaven国内源：<settings> <mirrors> <mirror> <id>aliyun</id> <mirrorOf>*</mirrorOf> <url>https://maven.aliyun.com/repository/public</url> </mirror> <mirror> <id>hwcloud</id> <mirrorOf>*</mirrorOf> <url>https://mirrors.huaweicloud.com/repository/maven/</url> </mirror> <mirror> <id>tsinghua</id> <mirrorOf>*</mirrorOf> <url>https://mirrors.tuna.tsinghua.edu.cn/maven/</url> </mirror> <mirror> <id>ustc</id> <mirrorOf>*</mirrorOf> <url>https://mirrors.ustc.edu.cn/maven/</url> </mirror> </mirrors> </settings>项目启动项目代码在docker内运行,使用docker-compose.yml管理。docker和docker-compose的安装见往期文章。构建docker镜像:{hide}# java8基础镜像 FROM registry.cn-hangzhou.aliyuncs.com/mybud/java18:lastest # 作者信息 MAINTAINER xxm1995@outlook.com # 时区设置 ENV TZ=Asia/Shanghai RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /…

新客户端IP一键过白功能开发与配置
type: item
date: 2024-08-21T09:08:00+00:00
description: 前言部署了一个自己使用的web服务，不想对公网开放。最初用iptables对自己当前的电脑IP开放，禁止其他IP访问。每次路由器重启，或者在外出差，IP经常变动。需要登录服务器，新增新的IP。决定改变控制方式，利用nginx的IP白名单功能，同时用flask写了一个对公网开放的页面。当地址变动时，访问此页面。点击一键更新，就把最新的ip加入到nginx的白名单。同时重新加载nginx配置生效。{card-default label="ip更新页面" width="85%"}{/card-default}被控制服务需要进行ip访问控制，不对公网开放的nginx配置信息。default.conf配置用加载了ip白名单文件whitelist.conf# Appadmin server { listen 80; server_name 0.0.0.0; root /www/web/maccms_v10/; server_tokens off; #include none.conf; index index.php index.html index.htm; access_log /www/web_logs/wp_access.log wwwlogs; error_log /www/web_logs/wp_error.log notice; #auth_basic "请输入用户和密码"; # 验证时的提示信息 #auth_basic_user_file /etc/nginx/password; # 认证文件 location /{ include whitelist.conf; #默认位置路径为/etc/nginx/ 下， #如直接写include whitelist.conf，则只需要在/etc/nginx目录下创建whitelist.conf deny all; } location ~ \.php$ { fastcgi_pass php:9000; fastcgi_index index.php; include fcgi.conf; } #需要注意伪静态的配置 if (!-e $request_filename) { rewrite ^/index.php(.*)$ /index.php?s=$1 last; rewrite ^/api.php(.*)$ /api.php?s=$1 last; rewrite ^/adm0.php(.*)$ /adm0.php?s=$1 last; rewrite ^(.*)$ /index.php?s=$1 last; break; } location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { expires 30d; } location ~ .*\.(js|css)?$ { expires 12h; } }whitelist.conf文件内存放需要开放的IP,文件内容：allow 101.31.158.153;控制服务文章开头的一键放通页面用flask框架实现, 单独部署app.py主要实现逻辑，有两个接口。一个接口提供页面，一个接口负责获取IP后更新，同时重新加载被控制服务的nginx配置{hide}from flask import Flask, request, render_template, jsonify import os app = Flask(__name__) # 定义首页路由，渲染包含按钮的HTML页面 @app.route('/') def index(): return render_template('index.html') # 定义处理客户端IP上传的路由 @app.route('/upload_ip', methods=['POST']) def upload_ip(): # 获取客户端的IP地址 #client_ip = request.remote_addr client_ip = request.headers.get('X-Forwarded-For') # 这里可以添加处理逻辑，比如将IP地址保存到数据库或文件 print(f"Client IP: {client_ip}") try: command = f"echo 'allow {client_ip};' > /srv/lnmp/services/nginx/conf/whitelist.conf && docker exec lnmp-web-1 /bin/bash -c 'nginx -s reload'" status = os.system(command) if status == 0: response = {'status': 'success'…

扫码点餐系统管理后台界面
type: item
date: 2024-07-31T12:22:15+00:00
description: 前言前几天搭建部署了扫码点餐平台，继续介绍平台的功能。本文主要分享管理员后台的相关界面首页登录系统后首先看到的是首页仪表盘，包含一些系统信息。{card-default label="首页仪表盘" width="85%"}{/card-default}设置设置包括站点设置、登录注册、功能设置、分佣设置、消息提醒、友情链接等{card-default label="设置界面" width="85%"}{/card-default}