基于 Spring Boot 3.1.5 和 以太坊区块链 技术构建的透明慈善援助平台,利用区块链的不可篡改性确保每一笔捐赠都公开、透明、可追溯。
- 📜 所有捐赠和援助金发放记录永久存储在以太坊区块链上
- ⚡ 智能合约自动执行,杜绝人为干预和资金挪用
- 🔍 交易记录不可篡改,支持公众实时验证
- 🙋♂️ 捐赠者:在线便捷捐赠,实时追踪资金流向
- 🙋♀️ 受助人:一站式申请,支持电子材料提交
- 👨💼 管理员:智能化审核系统,高效管理资金发放
- 👥 公众:透明查看所有交易记录,建立信任机制
- 📋 完整的受助人申请与多级审核流程
- 💰 实时资金池统计与可视化报表
- 📎 安全的文件上传与智能验证系统
- 📈 实时数据看板与智能分析
┌─────────────────────────────────────────────────────┐
│ 前端展示层 │
│ Thymeleaf + Bootstrap 5 + JavaScript │
├─────────────────────────────────────────────────────┤
│ 应用控制层 │
│ Spring MVC + RESTful API + WebSocket │
├─────────────────────────────────────────────────────┤
│ 业务逻辑层 │
│ Service Layer + Transaction + Validation │
├─────────────────────────────────────────────────────┤
│ 数据持久层 │
│ Spring Data JPA + PostgreSQL 15 + Redis Cache │
├─────────────────────────────────────────────────────┤
│ 区块链交互层 │
│ Web3J + Ethereum Smart Contract + Infura │
└─────────────────────────────────────────────────────┘
| 模块 | 核心功能 | 状态 | 技术实现 |
|---|---|---|---|
| 🌐 用户界面 | 响应式设计,支持PC/移动端 | ✅ | Bootstrap 5 + Thymeleaf |
| 💸 捐赠系统 | 以太坊捐赠,交易记录上链 | ✅ | Web3J + 智能合约 |
| 📝 受助人申请 | 在线申请,文件上传,状态追踪 | ✅ | Spring MVC + 文件上传 |
| 📋 审核管理 | 多级审核,困难程度智能评估 | ✅ | 工作流引擎 + AI评估 |
| 💰 资金管理 | 资金池统计,发放记录,审计 | ✅ | PostgreSQL + 事务管理 |
| 📁 文件管理 | 文档上传,安全存储,格式验证 | ✅ | 本地存储 + 云存储 |
| 🔐 权限控制 | 基于角色的访问控制 | ✅ | Spring Security 6 |
| 🔌 API接口 | RESTful API,区块链交互 | ✅ | Spring REST + OpenAPI |
| 📊 数据统计 | 实时数据看板,可视化图表 | ✅ | Chart.js + 数据分析 |
| 🚀 多环境部署 | 开发/测试/生产环境 | ✅ | Docker + Kubernetes |
- ☕ Java 17 或更高版本
- 📦 Maven 3.6+ 或 Gradle
- 🐘 PostgreSQL 12+ 数据库
- ⛓️ 以太坊节点 (Ganache/Infura/Alchemy)
- 🐳 Docker (可选,推荐用于部署)
# HTTPS 方式克隆
git clone https://github.com/Dingchunru/Poverty_Alleviation_Fund_Management_System.git
cd Poverty_Alleviation_Fund_Management_System
# 或使用 SSH 方式(需配置SSH密钥)
git clone [email protected]:Dingchunru/Poverty_Alleviation_Fund_Management_System.git# 使用 Docker 快速启动 PostgreSQL(推荐)
docker run --name aidfund-postgres \
-e POSTGRES_DB=aidfund \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=yourpassword \
-p 5432:5432 \
-d postgres:15-alpine
# 或手动创建数据库
createdb aidfund# 启动 Ganache 测试网络(开发环境)
npx ganache-cli \
--deterministic \
--mnemonic "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat" \
--networkId 1337 \
--port 8545 \
--accounts 10 \
--defaultBalanceEther 1000
# 🎯 Ganache 将提供10个测试账户,每个账户预存1000 ETH# 复制配置文件模板
cp src/main/resources/application.yml.example src/main/resources/application.yml
# 编辑配置文件
# 请根据实际情况修改数据库连接、区块链节点等配置
vim src/main/resources/application.yml# 方式1:Maven 直接运行(开发模式)
mvn spring-boot:run
# 方式2:打包后运行
mvn clean package
java -jar target/aid-fund-platform-1.0.0.jar
# 方式3:使用 Docker 运行(推荐生产环境)
docker build -t aid-fund-platform .
docker run -p 8080:8080 aid-fund-platform默认测试账号:
- 👑 管理员:
admin/admin123 - 💰 测试捐赠账户:使用 Ganache 提供的第一个账户
- 📝 合约地址:应用启动后从控制台获取
# 一键启动所有服务(数据库 + 区块链 + 应用)
docker-compose up -d
# 查看服务状态
docker-compose ps
# 实时查看应用日志
docker-compose logs -f app
# 停止所有服务
docker-compose down
# 停止并清理所有数据
docker-compose down -vversion: '3.8'
services:
# PostgreSQL 数据库
postgres:
image: postgres:15-alpine
environment:
POSTGRES_DB: aidfund
POSTGRES_USER: ${DB_USER:-postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:-password}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
# Ganache 区块链测试网络
ganache:
image: trufflesuite/ganache-cli:latest
command: [
"--mnemonic", "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat",
"--networkId", "1337",
"--accounts", "10",
"--defaultBalanceEther", "1000",
"--deterministic"
]
# 主应用服务
app:
build: .
environment:
SPRING_PROFILES_ACTIVE: docker
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/aidfund
BLOCKCHAIN_WEB3_PROVIDER: http://ganache:8545
ADMIN_USERNAME: ${ADMIN_USER:-admin}
ADMIN_PASSWORD: ${ADMIN_PASS:-admin123}
depends_on:
postgres:
condition: service_healthy
ganache:
condition: service_started
ports:
- "8080:8080"
volumes:
- uploads:/app/uploads
volumes:
postgres_data:
uploads:| 方法 | 端点 | 描述 | 认证要求 | 示例 |
|---|---|---|---|---|
GET |
/api/stats |
获取平台统计概览 | 无需认证 | curl http://localhost:8080/api/stats |
POST |
/api/donate |
提交捐赠交易 | 需要认证 | 见下方示例 |
GET |
/api/recipients |
获取受助人列表 | 无需认证 | curl "http://localhost:8080/api/recipients?status=approved" |
POST |
/api/recipients |
创建受助人申请 | 需要认证 | 见下方示例 |
GET |
/api/transactions |
获取交易记录 | 需要认证 | curl -u admin:admin123 http://localhost:8080/api/transactions |
GET |
/api/contract/info |
获取智能合约信息 | 无需认证 | curl http://localhost:8080/api/contract/info |
# 1. 获取平台统计数据
curl -X GET "http://localhost:8080/api/stats"
# 2. 提交捐赠交易(需携带认证信息)
curl -X POST "http://localhost:8080/api/donate" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"fromAddress": "0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1",
"amount": "1.5",
"message": "支持慈善事业,愿世界更美好",
"privateKey": "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d"
}'
# 3. 获取特定状态的受助人列表
curl -X GET "http://localhost:8080/api/recipients?status=approved&page=0&size=10"
# 4. 创建新的受助人申请
curl -X POST "http://localhost:8080/api/recipients" \
-H "Content-Type: application/json" \
-d '{
"walletAddress": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
"name": "张三",
"location": "北京市朝阳区",
"aidAmount": "5000",
"description": "家庭困难,需要医疗援助",
"difficultyLevel": 8
}'@Service
@Slf4j
public class ContractServiceImpl implements ContractService {
private final Web3j web3j;
private final Credentials adminCredentials;
@Override
@Transactional
public CompletableFuture<TransactionReceipt> processDonation(
String fromAddress,
BigDecimal amount) {
return CompletableFuture.supplyAsync(() -> {
try {
// 1. 验证捐赠者地址
if (!Web3Utils.isValidAddress(fromAddress)) {
throw new IllegalArgumentException("无效的以太坊地址");
}
// 2. 转换为 Wei 单位
BigInteger amountWei = Web3Utils.etherToWei(amount);
// 3. 构建捐赠交易
Function donateFunction = new Function(
"donate",
Collections.emptyList(),
Collections.emptyList()
);
String encodedFunction = FunctionEncoder.encode(donateFunction);
// 4. 获取当前 nonce
EthGetTransactionCount ethGetTransactionCount = web3j
.ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST)
.send();
BigInteger nonce = ethGetTransactionCount.getTransactionCount();
// 5. 创建原始交易
RawTransaction rawTransaction = RawTransaction.createTransaction(
nonce,
GAS_PRICE,
GAS_LIMIT,
contractAddress,
amountWei,
encodedFunction
);
// 6. 发送并确认交易
EthSendTransaction response = web3j
.ethSendRawTransaction(Numeric.toHexString(
TransactionEncoder.signMessage(rawTransaction, chainId, credentials)
))
.send();
if (response.hasError()) {
throw new BlockchainException("交易失败: " + response.getError().getMessage());
}
// 7. 等待交易确认
return waitForTransactionReceipt(response.getTransactionHash());
} catch (Exception e) {
log.error("捐赠处理失败", e);
throw new BlockchainException("区块链交易异常: " + e.getMessage());
}
});
}
}-- 受助人信息表
CREATE TABLE recipient_info (
id BIGSERIAL PRIMARY KEY,
wallet_address VARCHAR(42) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL,
location VARCHAR(200),
id_number VARCHAR(50),
contact VARCHAR(100),
aid_amount DECIMAL(36, 18) NOT NULL,
description TEXT,
difficulty_level INTEGER CHECK (difficulty_level BETWEEN 1 AND 10),
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
rejection_reason TEXT,
approved_by VARCHAR(100),
approved_at TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
on_chain_id INTEGER,
CONSTRAINT chk_aid_amount CHECK (aid_amount > 0)
);
-- 捐赠记录表
CREATE TABLE donation_record (
id BIGSERIAL PRIMARY KEY,
donor_address VARCHAR(42) NOT NULL,
donor_name VARCHAR(100) DEFAULT '匿名',
message TEXT,
amount DECIMAL(36, 18) NOT NULL,
transaction_hash VARCHAR(66) UNIQUE,
block_number BIGINT,
donated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
on_chain_id INTEGER,
INDEX idx_donor_address (donor_address),
INDEX idx_donated_at (donated_at)
);
-- 资金发放记录表
CREATE TABLE distribution_record (
id BIGSERIAL PRIMARY KEY,
recipient_id BIGINT NOT NULL REFERENCES recipient_info(id),
amount DECIMAL(36, 18) NOT NULL,
transaction_hash VARCHAR(66) UNIQUE,
distributed_by VARCHAR(100) NOT NULL,
distributed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
on_chain_id INTEGER,
INDEX idx_recipient_id (recipient_id),
INDEX idx_distributed_at (distributed_at)
);
-- 文件存储表
CREATE TABLE recipient_document (
id BIGSERIAL PRIMARY KEY,
recipient_id BIGINT NOT NULL REFERENCES recipient_info(id),
file_name VARCHAR(255) NOT NULL,
file_path TEXT NOT NULL,
file_size BIGINT,
content_type VARCHAR(100),
uploaded_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX idx_recipient_id (recipient_id)
);-- 为高频查询字段创建索引
CREATE INDEX idx_recipient_status ON recipient_info(status);
CREATE INDEX idx_recipient_created ON recipient_info(created_at DESC);
CREATE INDEX idx_donation_hash ON donation_record(transaction_hash);
CREATE INDEX idx_distribution_chain ON distribution_record(on_chain_id);
CREATE INDEX idx_document_recipient ON recipient_document(recipient_id);| 安全层面 | 实现技术 | 防护能力 |
|---|---|---|
| 认证授权 | Spring Security 6 + JWT | 基于角色的细粒度权限控制 |
| 数据安全 | BCrypt 密码加密 + TLS 1.3 | 防止密码泄露,确保传输安全 |
| 区块链安全 | 交易签名 + 智能合约权限 | 防止未授权区块链操作 |
| Web安全 | CSRF防护 + XSS过滤 | 防御常见Web攻击 |
| API安全 | 速率限制 + 请求验证 | 防止API滥用和注入攻击 |
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
@Slf4j
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// 1. CSRF配置(针对API禁用,针对表单启用)
.csrf(csrf -> csrf
.ignoringRequestMatchers("/api/**", "/webhook/**")
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
)
// 2. 请求授权配置
.authorizeHttpRequests(auth -> auth
// 公开访问的路径
.requestMatchers(
"/",
"/donate",
"/apply",
"/recipients/**",
"/api/stats",
"/api/contract/**",
"/css/**",
"/js/**",
"/images/**",
"/uploads/**"
).permitAll()
// 需要管理员权限的路径
.requestMatchers(
"/admin/**",
"/api/admin/**",
"/api/donate",
"/api/recipients"
).hasRole("ADMIN")
// 需要认证的API
.requestMatchers("/api/**").authenticated()
// 其他所有请求需要认证
.anyRequest().authenticated()
)
// 3. 表单登录配置
.formLogin(form -> form
.loginPage("/admin/login")
.loginProcessingUrl("/admin/login")
.defaultSuccessUrl("/admin/dashboard")
.failureUrl("/admin/login?error=true")
.permitAll()
)
// 4. 登出配置
.logout(logout -> logout
.logoutUrl("/admin/logout")
.logoutSuccessUrl("/")
.invalidateHttpSession(true)
.clearAuthentication(true)
.deleteCookies("JSESSIONID")
.permitAll()
)
// 5. 记住我功能
.rememberMe(remember -> remember
.key("uniqueAndSecret")
.tokenValiditySeconds(86400) // 24小时
)
// 6. 会话管理
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.maximumSessions(1)
.expiredUrl("/admin/login?expired=true")
)
// 7. 异常处理
.exceptionHandling(exceptions -> exceptions
.accessDeniedPage("/error/403")
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/admin/login"))
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // 高强度的密码加密
}
}# application.yml 配置示例
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
base-path: /manage
path-mapping:
health: health-check
endpoint:
health:
show-details: always
show-components: always
probes:
enabled: true
metrics:
enabled: true
prometheus:
enabled: true
metrics:
export:
prometheus:
enabled: true
distribution:
percentiles-histogram:
"[http.server.requests]": true| 端点路径 | 描述 | 用途 |
|---|---|---|
/manage/health |
应用健康状态 | 负载均衡健康检查 |
/manage/health/liveness |
存活探针 | Kubernetes 存活检查 |
/manage/health/readiness |
就绪探针 | Kubernetes 就绪检查 |
/manage/info |
应用信息 | 版本、构建信息 |
/manage/metrics |
应用指标 | JVM、HTTP请求等指标 |
/manage/prometheus |
Prometheus 格式指标 | 监控系统集成 |
/manage/loggers |
日志级别管理 | 动态调整日志级别 |
/manage/env |
环境变量 | 查看所有环境配置 |
logging:
level:
root: INFO
com.aidfund: DEBUG
org.web3j: INFO
org.springframework.security: WARN
org.hibernate.SQL: DEBUG
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) [%15.15t] %cyan(%logger{40}) : %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%t] %logger{40} : %msg%n"
file:
name: logs/aidfund-application.log
path: ./logs
max-size: 100MB
max-history: 30
total-size-cap: 3GB
logback:
rollingpolicy:
max-file-size: 100MB
file-name-pattern: logs/aidfund-application-%d{yyyy-MM-dd}.%i.log# 数据库配置
export SPRING_DATASOURCE_URL=jdbc:postgresql://production-db:5432/aidfund_prod
export SPRING_DATASOURCE_USERNAME=prod_user
export SPRING_DATASOURCE_PASSWORD=$(cat /run/secrets/db-password)
# 区块链配置
export BLOCKCHAIN_WEB3_PROVIDER=https://mainnet.infura.io/v3/${INFURA_PROJECT_ID}
export BLOCKCHAIN_CONTRACT_ADDRESS=0x...
export BLOCKCHAIN_ADMIN_ACCOUNT=0x...
export BLOCKCHAIN_ADMIN_PRIVATE_KEY=$(cat /run/secrets/blockchain-key)
# 应用配置
export ADMIN_USERNAME=production_admin
export ADMIN_PASSWORD=$(cat /run/secrets/admin-password)
export SERVER_PORT=8080
export SERVER_SSL_ENABLED=true
export SERVER_SSL_KEY_STORE=file:/app/ssl/keystore.p12
export SERVER_SSL_KEY_STORE_PASSWORD=$(cat /run/secrets/ssl-password)
# JVM 优化参数
export JAVA_OPTS="-Xmx2g -Xms1g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+ParallelRefProcEnabled \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/log/heapdump.hprof \
-XX:+UseContainerSupport \
-XX:InitialRAMPercentage=75.0 \
-XX:MaxRAMPercentage=75.0"# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
# 基础配置
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
# 性能优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 20M;
# Gzip 压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss
application/atom+xml image/svg+xml;
# HTTP 到 HTTPS 重定向
server {
listen 80;
server_name aidfund.org www.aidfund.org;
return 301 https://$server_name$request_uri;
}
# HTTPS 服务器配置
server {
listen 443 ssl http2;
server_name aidfund.org www.aidfund.org;
# SSL 证书配置
ssl_certificate /etc/ssl/certs/aidfund.crt;
ssl_certificate_key /etc/ssl/private/aidfund.key;
ssl_trusted_certificate /etc/ssl/certs/ca-bundle.crt;
# SSL 优化
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
# HSTS 安全头
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' cdn.jsdelivr.net; img-src 'self' data:; font-src 'self' cdn.jsdelivr.net;" always;
# 主应用代理
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# WebSocket 支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 缓冲区优化
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
root /var/www/aidfund/static;
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# 上传文件访问
location /uploads/ {
alias /var/www/aidfund/uploads/;
internal; # 只能通过应用访问
expires 30d;
add_header Cache-Control "public";
}
# 健康检查端点
location /manage/health {
proxy_pass http://localhost:8080/manage/health;
access_log off;
}
}
}- 📘 Spring Boot 官方文档 - 框架核心指南
- ⛓️ Web3J 官方文档 - 以太坊Java集成
- 🔗 以太坊开发文档 - 区块链开发指南
- 🐘 PostgreSQL 官方文档 - 数据库使用手册
- 🛡️ Spring Security 指南 - 安全框架详解
| 工具 | 用途 | 链接 |
|---|---|---|
| Ganache | 以太坊本地开发链 | 下载 |
| Infura/Alchemy | 以太坊节点服务 | Infura / Alchemy |
| Etherscan | 以太坊区块链浏览器 | 访问 |
| Metamask | 以太坊钱包插件 | 下载 |
| Postman | API测试与调试 | 下载 |
| DBeaver | 数据库管理工具 | 下载 |
- 💬 GitHub Issues - 问题反馈与讨论
- 🎯 Stack Overflow - 技术问答 #spring-boot #web3j
- 📖 官方文档Wiki - 项目详细文档
- 💡 最佳实践指南 - 查看
docs/目录下的详细指南
- Fork 仓库 - 点击页面右上角的 Fork 按钮
- 克隆分支 -
git clone [email protected]:your-username/Poverty_Alleviation_Fund_Management_System.git - 创建功能分支 -
git checkout -b feature/your-amazing-feature - 提交更改 -
git commit -m "feat: 添加了XX功能" - 推送到分支 -
git push origin feature/your-amazing-feature - 创建 Pull Request - 在 GitHub 页面发起合并请求
# 1. 代码格式化
mvn spotless:apply
# 2. 静态代码检查
mvn checkstyle:check
mvn pmd:check
mvn spotbugs:check
# 3. 运行测试
mvn test
# 4. 生成测试报告
mvn surefire-report:report我们遵循 Conventional Commits 规范:
<类型>[可选范围]: <描述>
[可选正文]
[可选脚注]
常用类型:
feat: 新功能fix: 修复bugdocs: 文档更新style: 代码格式调整refactor: 代码重构test: 测试相关chore: 构建过程或辅助工具的变动
示例:
git commit -m "feat(捐赠): 添加批量捐赠功能"
git commit -m "fix(审核): 修复审核状态更新问题"
git commit -m "docs(README): 更新部署指南"- 👨💻 Dingchunru - 项目创建者与主要维护者
- 📧 邮箱: [email protected]
- 🏫 学校: 北京邮电大学
| 渠道 | 用途 | 响应时间 |
|---|---|---|
| 🐛 GitHub Issues | Bug报告、功能请求 | 1-3个工作日 |
| 📖 项目Wiki | 详细文档、使用教程 | 实时更新 |
| 💬 电子邮件 | 正式咨询、合作意向 | 1-2个工作日 |
| 🔄 Pull Requests | 代码贡献、功能改进 | 及时审查 |
感谢以下开源项目和社区的支持:
- 🍃 Spring Boot 团队 - 提供强大的Java开发框架
- ⛓️ Web3J 贡献者 - 简化以太坊Java集成
- 🐘 PostgreSQL 社区 - 稳定可靠的关系数据库
- 🎨 Bootstrap 团队 - 优秀的前端框架
- 🤝 所有贡献者 - 感谢每一位参与改进的用户
本项目采用 MIT 许可证 - 查看 LICENSE 文件了解详情。
MIT License
Copyright (c) 2024 Dingchunru
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.