本系统采用微服务架构,前端使用Vue 3 + Element Plus,后端使用Spring Boot 2.7,数据库使用PostgreSQL 14,文件存储使用MinIO,全文检索使用Elasticsearch 8.5。
选择PostgreSQL是因为它对JSON数据的良好支持,便于存储证件结构化信息。MinIO提供S3兼容接口,适合存储扫描件。Elasticsearch用于实现快速的多条件检索。
在Ubuntu 22.04系统上执行以下命令:
安装Java 17:
``` sudo apt update sudo apt install openjdk-17-jdk java -version ```安装Node.js 18:
``` curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt install nodejs node --version ```安装PostgreSQL:
``` sudo apt install postgresql-14 postgresql-client-14 sudo systemctl start postgresql sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD 'YourPassword123';" ```下载并启动MinIO:
``` wget https://dl.min.io/server/minio/release/linux-amd64/minio chmod +x minio ./minio server /data/minio --console-address ":9001" ```访问http://localhost:9001,创建access key和secret key。
创建数据库:
``` CREATE DATABASE org_code_archive; \c org_code_archive; ```组织机构表:
``` CREATE TABLE organizations ( id SERIAL PRIMARY KEY, org_code VARCHAR(20) UNIQUE NOT NULL, org_name VARCHAR(200) NOT NULL, legal_representative VARCHAR(100), address TEXT, status VARCHAR(20), issue_date DATE, expiry_date DATE, metadata JSONB, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ```证件文件表:
``` CREATE TABLE certificate_files ( id SERIAL PRIMARY KEY, org_id INTEGER REFERENCES organizations(id), file_name VARCHAR(255), file_path VARCHAR(500), file_size BIGINT, mime_type VARCHAR(100), storage_type VARCHAR(20) DEFAULT 'minio', bucket_name VARCHAR(100), object_name VARCHAR(500), upload_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_valid BOOLEAN DEFAULT true ); ```使用Spring Initializr创建项目:
访问https://start.spring.io,选择:
application.yml配置:
``` server: port: 8080 spring: datasource: url: jdbc:postgresql://localhost:5432/org_code_archive username: postgres password: YourPassword123 driver-class-name: org.postgresql.Driver jpa: hibernate: ddl-auto: update show-sql: true minio: endpoint: http://localhost:9000 access-key: your-access-key secret-key: your-secret-key bucket: org-certificates ```创建MinIO配置类:
``` @Configuration public class MinioConfig { @Value("${minio.endpoint}") private String endpoint; @Value("${minio.access-key}") private String accessKey; @Value("${minio.secret-key}") private String secretKey; @Bean public MinioClient minioClient() { return MinioClient.builder() .endpoint(endpoint) .credentials(accessKey, secretKey) .build(); } } ```
文件上传接口实现:
``` @Service public class FileStorageService { @Autowired private MinioClient minioClient; @Value("${minio.bucket}") private String bucketName; public String uploadFile(MultipartFile file, String orgCode) { try { // 创建bucket(如果不存在) boolean found = minioClient.bucketExists(BucketExistsArgs.builder() .bucket(bucketName).build()); if (!found) { minioClient.makeBucket(MakeBucketArgs.builder() .bucket(bucketName).build()); } // 生成唯一文件名 String fileName = orgCode + "_" + System.currentTimeMillis() + "_" + file.getOriginalFilename(); // 上传文件 minioClient.putObject( PutObjectArgs.builder() .bucket(bucketName) .object(fileName) .stream(file.getInputStream(), file.getSize(), -1) .contentType(file.getContentType()) .build() ); return fileName; } catch (Exception e) { throw new RuntimeException("文件上传失败", e); } } } ```创建项目:
``` npm create vue@latest org-code-frontend cd org-code-frontend npm install npm install element-plus axios ```配置Element Plus:
``` // main.js import { createApp } from 'vue' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' import App from './App.vue' const app = createApp(App) app.use(ElementPlus) app.mount('app') ```创建UploadCertificate.vue:
```安装Tesseract:
``` sudo apt install tesseract-ocr sudo apt install tesseract-ocr-chi-sim ```Java集成代码:
```OCR服务类:
``` @Service public class OcrService { public String extractTextFromImage(File imageFile) { try { ITesseract tesseract = new Tesseract(); tesseract.setDatapath("/usr/share/tesseract-ocr/4.00/tessdata"); tesseract.setLanguage("chi_sim+eng"); return tesseract.doOCR(imageFile); } catch (Exception e) { throw new RuntimeException("OCR识别失败", e); } } } ```安装Elasticsearch:
``` docker run -d --name elasticsearch \ -p 9200:9200 -p 9300:9300 \ -e "discovery.type=single-node" \ -e "xpack.security.enabled=false" \ elasticsearch:8.5.3 ```创建索引:
``` PUT /org_certificates { "mappings": { "properties": { "orgCode": {"type": "keyword"}, "orgName": { "type": "text", "analyzer": "ik_max_word" }, "legalRepresentative": {"type": "text"}, "address": {"type": "text"}, "issueDate": {"type": "date"}, "content": { "type": "text", "analyzer": "ik_smart" } } } } ```创建Dockerfile:
``` FROM openjdk:17-jdk-slim WORKDIR /app COPY target/org-code-archive-0.0.1-SNAPSHOT.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"] ```构建镜像:
``` docker build -t org-code-backend . docker run -d -p 8080:8080 --name org-code-app org-code-backend ```/etc/nginx/sites-available/org-code.conf:
``` server { listen 80; server_name your-domain.com; location / { root /var/www/org-code-frontend/dist; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://localhost:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /minio/ { proxy_pass http://localhost:9000/; } } ```创建备份脚本backup.sh:
``` !/bin/bash BACKUP_DIR="/backup/org_code" DATE=$(date +%Y%m%d_%H%M%S) 备份数据库 pg_dump -U postgres org_code_archive > \ $BACKUP_DIR/db_backup_$DATE.sql 备份MinIO数据 mc mirror --overwrite minio/org-certificates \ $BACKUP_DIR/minio_backup_$DATE/ 压缩备份文件 tar -czf $BACKUP_DIR/backup_$DATE.tar.gz \ $BACKUP_DIR/db_backup_$DATE.sql \ $BACKUP_DIR/minio_backup_$DATE/ 删除临时文件 rm $BACKUP_DIR/db_backup_$DATE.sql rm -rf $BACKUP_DIR/minio_backup_$DATE/ 保留最近7天备份 find $BACKUP_DIR -name ".tar.gz" -mtime +7 -delete ```设置定时任务:
``` crontab -e 每天凌晨2点执行备份 0 2 /bin/bash /scripts/backup.sh ```Spring Boot启用监控:
```application.yml添加:
``` management: endpoints: web: exposure: include: health,info,prometheus metrics: export: prometheus: enabled: true ```