python: DDD using postgeSQL and SQL Server
postgreSQL
注意:
# psycopg 2 驱动的连接字符串
#engine = create_engine('postgresql://post:geovindu@localhost:5433/TechnologyGame')
#Session = sessionmaker(bind=engine)# 使用 psycopg3 驱动的连接字符串
#engine = create_engine('postgresql+psycopg://user:geovindu@localhost:5432/TechnologyGame')
#Session = sessionmaker(bind=engine)
create table School -- 創建表
(SchoolId char(5) NOT NULL PRIMARY KEY, SchoolName varchar(500) NOT NULL DEFAULT '', SchoolTelNo varchar(8) NULL DEFAULT ''
);create table Teacher -- 創建表
(TeacherId char(5) NOT NULL ,TeacherFirstName varchar(100) NOT NULL DEFAULT '', TeacherLastName varchar(20) NOT NULL DEFAULT '',TeacherGender char(2) NOT NULL DEFAULT '',TeacherTelNo varchar(8) NULL DEFAULT '',TeacherSchoolId char(5) NOT NULL DEFAULT '', PRIMARY KEY (TeacherId), -- 主鍵FOREIGN KEY(TeacherSchoolId) REFERENCES School(SchoolId) -- 外鍵
);
项目结构:

# encoding: utf-8
# 版权所有 2025 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author : geovindu,Geovin Du 涂聚文.
# IDE : PyCharm 2023.1 python 3.11
# OS : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 oracle 21c Neo4j
# Datetime : 2025/3/6 22:51
# User : geovindu
# Product : PyCharm
# Project : pypostgreSQLDDDOrmDemo
# File : teacher.py
# explain : 学习
from sqlalchemy import create_engine, Column, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, declarative_base, relationshipBase = declarative_base()''' '''
class SchoolModel(Base):"""必须小写字母"""__tablename__ = 'school'schoolid = Column(String(5), primary_key=True)schoolname = Column(String(500), default='')schooltelno = Column(String(8), default='')teachers = relationship("TeacherModel", back_populates="school")class TeacherModel(Base):"""必须小写字母"""__tablename__ = 'teacher'teacherid = Column(String(5), primary_key=True)teacherfirstname = Column(String(100), default='')teacherlastname = Column(String(20), default='')teachergender = Column(String(2), default='')teachertelno = Column(String(8), default='')teacherschoolid = Column(String(5), ForeignKey(SchoolModel.schoolid))school = relationship("SchoolModel", back_populates="teachers")
# encoding: utf-8
# 版权所有 2025 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author : geovindu,Geovin Du 涂聚文.
# IDE : PyCharm 2023.1 python 3.11
# OS : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 oracle 21c Neo4j
# Datetime : 2025/3/6 22:58
# User : geovindu
# Product : PyCharm
# Project : pypostgreSQLDDDOrmDemo
# File : teacher.py
# explain : 学习
from domain.repositories.teacher import TeacherRepository
from infrastructure.database.postgresqlHelper import PostgresqlHelper
from infrastructure.model.teacher import TeacherModel
from domain.entities.teacher import Teacherclass TeacherRepositoryImpl(TeacherRepository):""""""def __init__(self):self.sesion = PostgresqlHelper()def get_all(self, page=1, page_size=10, keyword=''):""":param page::param page_size::param keyword::return:"""session = self.sesion.getSession()try:offset = (page - 1) * page_sizequery = session.query(TeacherModel)print(query)#query = query.order_by(TeacherModel.teacherid)#total = query.count()#print("total", total)if keyword:query = query.filter((TeacherModel.teacherfirstname.contains(keyword)) |(TeacherModel.teacherlastname.contains(keyword)))teachers =query.offset(offset).limit(page_size).all() # query.offset(offset).limit(page_size).all()print("data teachers",teachers)return [Teacher(teacher.teacherid, teacher.teacherfirstname, teacher.teacherlastname, teacher.teachergender, teacher.teachertelno, teacher.teacherschoolid) for teacher in teachers]except Exception as ex:print(ex.__str__())print(f"Error fetching teachers: {ex}")#return [] # 返回空列表而不是 Nonefinally:session.close()def get_by_id(self, teacher_id):""":param teacher_id::return:"""session = self.sesion.getSession()try:teacher = session.query(TeacherModel).filter_by(teacher_id=teacher_id).first()if teacher:return Teacher(teacher.teacherid, teacher.teacherfirstname, teacher.teacherlastname, teacher.teachergender, teacher.teachertelno, teacher.teacherschoolid)return Nonefinally:session.close()def add(self, teacher: Teacher):""":param teacher::return:"""session = self.sesion.getSession()try:new_teacher = TeacherModel(teacher_id=teacher.teacher_id, first_name=teacher.first_name, last_name=teacher.last_name, gender=teacher.gender, tel_no=teacher.tel_no, school_id=teacher.school_id)session.add(new_teacher)session.commit()except:session.rollback()raisefinally:session.close()def update(self, teacher: Teacher):""":param teacher::return:"""session = self.sesion.getSession()try:existing_teacher = session.query(TeacherModel).filter_by(teacher_id=teacher.teacher_id).first()if existing_teacher:existing_teacher.first_name = teacher.first_nameexisting_teacher.last_name = teacher.last_nameexisting_teacher.gender = teacher.genderexisting_teacher.tel_no = teacher.tel_noexisting_teacher.school_id = teacher.school_idsession.commit()except:session.rollback()raisefinally:session.close()def delete(self, teacher_id):""":param teacher_id::return:"""session = self.sesion.getSession()try:teacher = session.query(TeacherModel).filter_by(teacher_id=teacher_id).first()if teacher:session.delete(teacher)session.commit()except:session.rollback()raisefinally:session.close()def get_total_count(self, keyword=''):""":param keyword::return:"""session = self.sesion.getSession()try:query = session.query(TeacherModel)if keyword:query = query.filter((TeacherModel.first_name.contains(keyword)) |(TeacherModel.last_name.contains(keyword)))count = query.count()return countexcept Exception as e:print(f"Error getting total count: {e}")return 0finally:session.close()
sql server:
create table School -- 創建表
(SchoolId char(5) NOT NULL PRIMARY KEY, -- 學校編號SchoolName nvarchar(500) NOT NULL DEFAULT '', -- 學校名稱',SchoolTelNo varchar(8) NULL DEFAULT '' , -- 電話號碼 );
create table Teacher -- 創建表
(TeacherId char(5) NOT NULL , --'主鍵primary key,學生編號',TeacherFirstName nvarchar(100) NOT NULL DEFAULT '', -- ' 名',TeacherLastName nvarchar(20) NOT NULL DEFAULT '', -- ' 姓',TeacherGender char(2) NOT NULL DEFAULT '', -- '性別',TeacherTelNo varchar(8) NULL DEFAULT '', --'電話號碼',TeacherSchoolId char(5) NOT NULL DEFAULT '', -- '外鍵 foreign key 學校ID', PRIMARY KEY (TeacherId), -- 主鍵FOREIGN KEY(TeacherSchoolId) REFERENCES School(SchoolId) -- 外鍵
)
项目结构:

# encoding: utf-8
# 版权所有 2025 ©涂聚文有限公司 ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author : geovindu,Geovin Du 涂聚文.
# IDE : PyCharm 2023.1 python 3.11
# OS : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 oracle 21c Neo4j
# Datetime : 2025/2/20 20:46
# User : geovindu
# Product : PyCharm
# Project : pyMsSqlDDDOrmDemo
# File : infrastructure/model/teacher.py
# explain : 学习
from sqlalchemy import create_engine, Column, String, ForeignKey
from sqlalchemy.orm import sessionmaker, declarative_base, relationship
from ..database.mssqlHelper import MssqlHelperBase = declarative_base()class SchoolModel(Base):"""基础设施层(Infrastructure)数据库交互"""__tablename__ = 'School'SchoolId = Column(String(5), primary_key=True)SchoolName = Column(String(500), default='')SchoolTelNo = Column(String(8), default='')teachers = relationship("TeacherModel", back_populates="school")class TeacherModel(Base):"""基础设施层(Infrastructure)数据库交互"""__tablename__ = 'Teacher'TeacherId = Column(String(5), primary_key=True)TeacherFirstName = Column(String(100), default='')TeacherLastName = Column(String(20), default='')TeacherGender = Column(String(2), default='')TeacherTelNo = Column(String(8), default='')TeacherSchoolId = Column(String(5), ForeignKey('School.SchoolId'))school = relationship("SchoolModel", back_populates="teachers")
# encoding: utf-8
# 版权所有 2025 ©涂聚文有限公司 ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author : geovindu,Geovin Du 涂聚文.
# IDE : PyCharm 2023.1 python 3.11
# OS : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 oracle 21c Neo4j
# Datetime : 2025/2/20 20:47
# User : geovindu
# Product : PyCharm
# Project : pyMsSqlDDDOrmDemo
# File : infrastructure/repositories/teacher.py
# explain : 学习from sqlalchemy import create_engine, Column, String, ForeignKey
from sqlalchemy.orm import sessionmaker, declarative_base, relationship
from domain.entities.teacher import Teacher
from domain.entities.school import School
from ..database.mssqlHelper import MssqlHelper
from ..model.teacher import TeacherModel
from sqlalchemy.exc import SQLAlchemyErrorclass TeacherRepository:"""基础设施层(Infrastructure)实现存储库接口"""def __init__(self):""""""self._Session = MssqlHelper()def add(self, teacher: Teacher):""":param teacher::return:"""session = self._Session.getSession()teacher_model = TeacherModel(TeacherId=teacher.teacher_id, TeacherFirstName=teacher.first_name,TeacherLastName=teacher.last_name, TeacherGender=teacher.gender,TeacherTelNo=teacher.tel_no, TeacherSchoolId=teacher.school_id)session.add(teacher_model)session.commit()session.close()def update(self, teacher: Teacher):""":param teacher::return:"""session = self._Session.getSession()teacher_model = session.query(TeacherModel).filter_by(TeacherId=teacher.teacher_id).first()if teacher_model:teacher_model.TeacherFirstName = teacher.first_nameteacher_model.TeacherLastName = teacher.last_nameteacher_model.TeacherGender = teacher.genderteacher_model.TeacherTelNo = teacher.tel_noteacher_model.TeacherSchoolId = teacher.school_idsession.commit()session.close()def update_teacher_and_school(self, teacher_id, first_name, last_name, gender, tel_no, school_id, school_name,school_tel_no):""":param teacher_id::param first_name::param last_name::param gender::param tel_no::param school_id::param school_name::param school_tel_no::return:"""session = self._Session.getSession()try:# 更新老师信息teacher = session.query(Teacher).filter_by(TeacherId=teacher_id).first()if teacher:teacher.TeacherFirstName = first_nameteacher.TeacherLastName = last_nameteacher.TeacherGender = genderteacher.TeacherTelNo = tel_noteacher.TeacherSchoolId = school_id# 更新关联学校信息school = session.query(School).filter_by(SchoolId=school_id).first()if school:school.SchoolName = school_nameschool.SchoolTelNo = school_tel_nosession.commit()except Exception as e:session.rollback()raise efinally:session.close()def delete(self, teacher_id: str):""":param teacher_id::return:"""session = self._Session.getSession()teacher_model = session.query(TeacherModel).filter_by(TeacherId=teacher_id).first()if teacher_model:session.delete(teacher_model)session.commit()session.close()def get_all(self, page: int, page_size: int, search_query: str = ""):""":param page::param page_size::param search_query::return:"""session = self._Session.getSession()query = session.query(TeacherModel)if search_query:query = query.filter((TeacherModel.TeacherId.contains(search_query)) |(TeacherModel.TeacherFirstName.contains(search_query)) |(TeacherModel.TeacherLastName.contains(search_query)) |(TeacherModel.TeacherGender.contains(search_query)) |(TeacherModel.TeacherTelNo.contains(search_query)) |(TeacherModel.TeacherSchoolId.contains(search_query)))offset = (page - 1) * page_sizequery = query.order_by(TeacherModel.TeacherId) # 这里以 TeacherId 为例进行排序,你可以根据实际需求修改排序字段total = query.count()#print(" teacher total", total)teacher_models = query.offset(offset).limit(page_size).all()session.close()return [Teacher(teacher.TeacherId, teacher.TeacherFirstName, teacher.TeacherLastName,teacher.TeacherGender, teacher.TeacherTelNo, teacher.TeacherSchoolId)for teacher in teacher_models]def get_total_count(self, search_query: str = ""):""":param search_query::return:"""session = self._Session.getSession()query = session.query(TeacherModel)if search_query:query = query.filter((TeacherModel.TeacherId.contains(search_query)) |(TeacherModel.TeacherFirstName.contains(search_query)) |(TeacherModel.TeacherLastName.contains(search_query)) |(TeacherModel.TeacherGender.contains(search_query)) |(TeacherModel.TeacherTelNo.contains(search_query)) |(TeacherModel.TeacherSchoolId.contains(search_query)))count = query.count()session.close()return count
输出:

相关文章:
python: DDD using postgeSQL and SQL Server
postgreSQL 注意: # psycopg 2 驱动的连接字符串 #engine create_engine(postgresql://post:geovindulocalhost:5433/TechnologyGame) #Session sessionmaker(bindengine)# 使用 psycopg3 驱动的连接字符串 #engine create_engine(postgresqlpsycopg://user:g…...
Python实例:PyMuPDF实现PDF翻译,英文翻译为中文,并按段落创建中文PDF
基于PyMuPDF与百度翻译的PDF翻译处理系统开发:中文乱码解决方案与自动化排版实践 一 、功能预览:将英文翻译为中文后创建的PDF 二、完整代码 from reportlab.lib.pagesizes import letter from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle...
IntelliJ IDEA 2021版创建springboot项目的五种方式
第一种方式,通过https://start.spring.io作为spring Initializr的url来创建项目。 第二种方式,通过https://start.spring.io官网来直接创建springboot项目压缩包,然后导入至我们的idea中。 点击generate后,即可生成压缩包…...
c#面试题整理6
1.String类能否被继承,为什么 可以看到String类的修饰符是sealed,即是密封类,故不可被继承 2.一个对象的方法是否只能由一个线程访问 不是,但是可通过同步机制,确保同一个时间只有一个线程访问 3.计算2*8ÿ…...
跟着 Lua 5.1 官方参考文档学习 Lua (12)
文章目录 5.7 – Input and Output Facilities补充内容io.input ([file])io.read ()io.write ()io.output ([file])io.lines ([filename])io.flush ()io.close ([file])io.open (filename [, mode])io.popen (prog [, mode])io.tmpfile ()io.type (ob)file:read ()file:lines (…...
大语言模型中的归一化技术:LayerNorm与RMSNorm的深入研究
在LLama等大规模Transformer架构的语言模型中,归一化模块是构建网络稳定性的关键组件。本文将系统分析归一化技术的必要性,并详细阐述为何原始Transformer架构中的LayerNorm在LLama模型中被RMSNorm所替代的技术原理。 归一化技术的基础原理 归一化的核…...
nodejs使用WebSocket实现聊天效果
在nodejs中使用WebSocket实现聊天效果(简易实现) 安装 npm i ws 实现 创建 server.js /*** 创建一个 WebSocket 服务器,监听指定端口,并处理客户端连接和消息。** param {Object} WebSocket - 引入的 WebSocket 模块,…...
【仿muduo库one thread one loop式并发服务器实现】
文章目录 一、项目介绍1-1、项目总体简介1-2、项目开发环境1-3、项目核心技术1-4、项目开发流程1-5、项目如何使用 二、框架设计2-1、功能模块划分2-1-1、SERVER模块2-1-2、协议模块 2-2、项目蓝图2-2-1、整体图2-2-2、模块关系图2-2-2-1、Connection 模块关系图2-2-2-2、Accep…...
10.2 继承与多态
文章目录 继承多态 继承 继承的作用是代码复用。派生类自动获得基类的除私有成员外的一切。基类描述一般特性,派生类提供更丰富的属性和行为。在构造派生类时,其基类构造函数先被调用,然后是派生类构造函数。在析构时顺序刚好相反。 // 基类…...
Go红队开发—格式导出
文章目录 输出功能CSV输出CSV 转 结构体结构体 转 CSV端口扫描结果使用CSV格式导出 HTML输出Sqlite输出nmap扫描 JSONmap转json结构体转jsonjson写入文件json编解码json转结构体json转mapjson转string练习:nmap扫描结果导出json格式 输出功能 在我们使用安全工具的…...
线性代数之矩阵特征值与特征向量的数值求解方法
文章目录 前言1. 幂迭代法(Power Iteration)幂法与反幂法求解矩阵特征值幂法求最大特征值编程实现补充说明 2. 逆幂迭代法(Inverse Iteration)移位反幂法 3. QR 算法(QR Algorithm)——稠密矩阵理论推导编程…...
Spring MVC源码分析のinit流程
文章目录 前言一、 init1.1、createWebApplicationContext1.2、onRefresh 二、请求处理器2.1、RequestMapping2.2、Controller接口2.3、HttpRequestHandler接口2.4、HandlerFunction 三、initHandlerMappings3.1、getDefaultStrategies3.1.1、RequestMappingHandlerMapping3.1.…...
【后端开发】go-zero微服务框架实践(goland框架对比,go-zero开发实践,文件上传问题优化等等)
【后端开发】go-zero微服务框架实践(goland框架对比,go-zero开发实践,文件上传问题优化等) 文章目录 1、go框架对比介绍2、go-zero 微服务开发实践3、go-zero 文件上传问题优化 1、go框架对比介绍 国内开源goland框架对比 1 go-…...
C#程序加密与解密Demo程序示例
目录 一、加密程序功能介绍 1、加密用途 2、功能 3、程序说明 4、加密过程 5、授权的注册文件保存方式 二、加密程序使用步骤 1、步骤一 编辑2、步骤二 3、步骤三 4、步骤四 三、核心代码说明 1、获取电脑CPU 信息 2、获取硬盘卷标号 3、机器码生成 3、 生成…...
小程序事件系统 —— 33 事件传参 - data-*自定义数据
事件传参:在触发事件时,将一些数据作为参数传递给事件处理函数的过程,就是事件传参; 在微信小程序中,我们经常会在组件上添加一些自定义数据,然后在事件处理函数中获取这些自定义数据,从而完成…...
深入解析 JavaScript 原型与原型链:从原理到应用
原型和原型链是 JavaScript 中实现对象继承和属性查找的核心机制。为了更深入地理解它们,我们需要从底层原理、实现机制以及实际应用等多个角度进行分析。 1. 原型(Prototype) 1.1 什么是原型? 每个 JavaScript 对象(…...
关于AI数据分析可行性的初步评估
一、结论:可在部分环节嵌入,无法直接处理大量数据 1.非本地部署的AI应用处理非机密文件没问题,内部文件要注意数据安全风险。 2.AI(指高规格大模型)十分适合探索性研究分析,对复杂报告无法全流程执行&…...
回归预测 | Matlab实现GWO-BP-Adaboost基于灰狼算法优化BP神经网络结合Adaboost思想的回归预测
回归预测 | Matlab实现GWO-BP-Adaboost基于灰狼算法优化BP神经网络结合Adaboost思想的回归预测 目录 回归预测 | Matlab实现GWO-BP-Adaboost基于灰狼算法优化BP神经网络结合Adaboost思想的回归预测回归效果基本介绍GWO-BP-Adaboost:基于灰狼算法优化BP神经网络结合Adaboost思想…...
ARM Cortex-M 内存映射详解:如何基于寄存器直接读写 寄存器映射方式编码程序 直接操作硬件寄存器来控制 MCU
ARM Cortex-M 的系统映射空间 在 STM32 等 ARM Cortex-M 系列 MCU 中,内存地址空间按照 存储功能 进行了严格划分,包括 Flash(程序存储)、RAM(数据存储)、外设寄存器(GPIO、UART、SPI 等&am…...
深度学习实战车辆目标跟踪与计数
本文采用YOLOv8作为核心算法框架,结合PyQt5构建用户界面,使用Python3进行开发。YOLOv8以其高效的实时检测能力,在多个目标检测任务中展现出卓越性能。本研究针对车辆目标数据集进行训练和优化,该数据集包含丰富的车辆目标图像样本…...
Qwen2-VL-2B-Instruct助力Java开发:智能代码注释与文档生成实战
Qwen2-VL-2B-Instruct助力Java开发:智能代码注释与文档生成实战 写Java代码最烦什么?对我来说,除了调试那些神出鬼没的Bug,就是写注释和文档了。明明代码逻辑自己一清二楚,但要把它转化成清晰、规范的文档,…...
AgiBot World数据集实战:如何用百万级轨迹训练你的机器人策略(附避坑指南)
AgiBot World数据集实战:百万级轨迹训练机器人策略的完整指南 1. 数据集的革命性价值 在机器人学习领域,数据质量与规模直接决定了策略模型的性能上限。AgiBot World作为当前最大的开源机器人操作数据集,其核心突破在于: 规模突…...
基于MATLAB的图像加密解密系统 可以正确无误的对图像进行加密和解密 带GUI界面
基于MATLAB的图像加密解密系统 可以正确无误的对图像进行加密和解密 带GUI界面,一步一步完整运行你是否有过这样的疑问——如何让一张普通图片变成外星密文?在MATLAB里玩转图像加密真的可以像搭积木一样简单。今天咱们就来捣鼓一个带界面的图像加密系统&…...
掌握NLP实践:从环境搭建到应用部署的6步学习指南
掌握NLP实践:从环境搭建到应用部署的6步学习指南 【免费下载链接】nlp-tutorial A list of NLP(Natural Language Processing) tutorials 项目地址: https://gitcode.com/gh_mirrors/nlp/nlp-tutorial 自然语言处理(NLP)作为人工智能领…...
AI手势识别从入门到应用:彩虹骨骼版MediaPipe Hands全流程解析
AI手势识别从入门到应用:彩虹骨骼版MediaPipe Hands全流程解析 1. 手势识别技术概述 手势识别作为人机交互的重要分支,正在改变我们与数字世界的互动方式。想象一下,无需触碰任何设备,仅凭手势就能控制音乐播放、浏览照片或操作…...
Linux g++编译与GDB调试完整流程(文末附图)
验证安装 C which g g --versionC which gcc gcc --version安装 **centOs**:sudo yum install gcc **centOs**:sudo yum install g **ubuntu**:sudo apt-get install gcc **ubuntu**:sudo apt-get install g **kyLin**:…...
springboot-vue+nodejs的电子产品商城销售平台
目录技术栈选择系统架构设计核心功能模块开发环境搭建数据库设计接口规范定义安全防护措施性能优化策略测试与部署项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作技术栈选择 后端采用Spring Boot框架,提供RESTful …...
OpenClaw跨平台脚本:Qwen3-32B生成的Python代码自动测试
OpenClaw跨平台脚本:Qwen3-32B生成的Python代码自动测试 1. 为什么需要AI全流程编程辅助 作为经常需要写脚本处理数据的开发者,我发现自己陷入了一个典型困境:每天要花大量时间编写重复性代码,而真正需要创造性思考的部分反而被…...
比迪丽FLUX.1效果对比:相比SDXL,面部结构准确率提升18.7%
比迪丽FLUX.1效果对比:相比SDXL,面部结构准确率提升18.7% 1. 引言:当动漫角色遇上新一代AI绘画引擎 如果你是一位《龙珠》的粉丝,或者热衷于用AI生成动漫角色,那么“比迪丽”这个名字你一定不陌生。作为悟饭的妻子&a…...
5个步骤让你的魔兽争霸3在现代电脑上完美运行:WarcraftHelper终极优化指南
5个步骤让你的魔兽争霸3在现代电脑上完美运行:WarcraftHelper终极优化指南 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 你是否还在为魔…...
