Files

7.7 KiB

CLAUDE.md - system-admin

This file provides guidance to Claude Code when working in the system-admin module.

Purpose

Main Spring Boot application module. Entry point: com.weather.AdminApplication. Depends on system-common and system-dynamic-datasource.

Module Structure

com.weather/
├── AdminApplication.java          # @SpringBootApplication, @EnableAsync
├── common/                        # Module-level shared code
│   ├── annotation/                # @DataFilter, @LogOperation
│   ├── aspect/                    # DataFilterAspect, LogOperationAspect
│   ├── config/                    # JacksonConfig, MybatisPlusConfig, SwaggerConfig, FileServerConfig
│   ├── exception/                 # CustomExceptionHandler
│   ├── handler/                   # FieldMetaObjectHandler (MyBatis-Plus auto-fill)
│   ├── interceptor/               # DataFilterInterceptor, DataScope
│   ├── utils/                     # ExcelUtils, TimeUtils
│   └── validator/group/           # Cloud storage validator groups
└── modules/
    ├── job/                       # Quartz scheduling
    ├── log/                       # Audit logs (operation, login, error)
    ├── oss/                       # Cloud file storage (Alibaba/Qiniu/Tencent)
    ├── region/                    # Geographic region tree
    ├── security/                  # Shiro auth, OAuth2 filter, login
    ├── sys/                       # System management (users, roles, menus, depts, dicts, params, alerts)
    └── weather/                   # Weather domain
        ├── dailydata/             # Daily weather data CRUD, import, caching
        ├── filescan/              # WatchService file scanning pipeline
        └── station/               # Weather station management

Service Layer Pattern

All business modules follow this structure under modules/<domain>/:

controller/   → @RestController, delegates to service interface
service/      → Interface extends CrudService<Entity, Dto>
service/impl/ → Extends CrudServiceImpl<Dao, Entity, Dto>, implements getWrapper()
dao/          → Interface extends BaseDao / BaseMapper
entity/       → Extends BaseEntity, maps to DB table
dto/          → Request/response DTOs
excel/        → @ExcelProperty-annotated beans for EasyExcel import/export

Entity-to-DTO conversion uses ConvertUtils.sourceToTarget().

Security / Auth

  • Framework: Apache Shiro with Jakarta-compatible artifacts (classifier: jakarta)
  • Token flow: Client sends token header/param -> Oauth2Filter extracts it -> Oauth2Realm validates against sys_user_token table -> returns UserDetail (user + dept scope + permissions)
  • Public paths (no auth): /login, /captcha, /druid/**, /doc.html, /swagger/**, /v3/api-docs/**, /favicon.ico
  • Password hashing: Custom BCryptPasswordEncoder with PasswordUtils (configurable rounds via sys_params)
  • Async context: UserContextHolder (ThreadLocal) preserves user context across async task boundaries (used in file import, scheduled tasks). SecurityUser.getUser() falls back to this when Shiro Subject is unavailable.

Data Scoping (Dept-Based Row-Level Security)

DataFilterInterceptor is a MyBatis-Plus InnerInterceptor. When a service method is annotated with @DataFilter, the DataFilterAspect injects a DataScope object containing a SQL filter clause into the query parameters. The interceptor then appends this WHERE clause to the SQL, restricting results to the user's authorized departments.

Example service usage:

@DataFilter
public PageData<Dto> page(Map<String, Object> params) {
    // SQL automatically filtered by dept scope
}

File Scanning Pipeline

FileWatchServiceManager (modules/weather/filescan/) monitors {FILE_SCAN_ROOT_PATH}/receive/ using java.nio.file.WatchService:

  1. Directory layout: receive/<deptName>/, display/<deptName>/, archive/<deptName>/
  2. Detection: WatchService detects ENTRY_CREATE and ENTRY_MODIFY events
  3. Wait: waitForFileReady() polls file size stability + file lock to ensure write completion
  4. Dedup: MD5 hash check against weather_file_scan_record table
  5. Parse: FileNameParser extracts region, category, period from filename
  6. Store: Record inserted; file copied to display/; old version moved to archive/
  7. Root files: Files in receive/ root (no dept subdir) are classified as "model forecast" with deptId = null

FileScanStartupRunner (ApplicationRunner) triggers full directory scan + WatchService registration on startup.

Weather Daily Data

Core table: weather_daily_data (entity: WeatherDailyDataEntity). Fields: stationId, observeDate, avgTemp, maxTemp/minTemp (with time), rainfall (20-20 and 08-08), relativeHumidity, atmospheres, wind (avg/max/extreme speed + direction + time), deptId.

Import Flow

WeatherDataImportManager handles Excel uploads:

  1. Save MultipartFile to temp file
  2. Submit async task (CompletableFuture), returns taskId immediately
  3. First pass: EasyExcel.read() with count listener to get total rows
  4. Second pass: WeatherDataListener reads rows in batches, calls insertBatch()
  5. insertBatch() resolves station-to-dept mapping, fills audit fields, uses insertBatchMultiRow() (custom MySQL multi-row INSERT)
  6. Clears weather summarize Redis cache on completion
  7. Progress tracked in-memory (ConcurrentHashMap<String, ImportProgress>)

Summarize Caching

WeatherSummarizeCacheTask (Quartz job) precomputes "same month-day across years" summary data per station into Redis. Cache key: weather:summarize:{month}:{day}. On cache hit, getCachedSummarize() filters by station + year range. On miss, falls back to selectSummarizeByMonthDay() DB query.

Alert / Notification System

  • Storage: SysAlertEntity in sys_alert table
  • Real-time push: SseAlertService manages active SSE connections (CopyOnWriteArraySet<SseEmitter>), broadcasts on Spring events:
    • AlertCreatedEvent -> SSE event alert
    • AlertWithdrawnEvent -> SSE event alert-withdrawn
    • AlertDeletedEvent -> SSE event alert-deleted
  • External sources: AlertSourcePollingTask (Quartz) polls external services; AlertSourceCollector gathers results

Job Scheduling (Quartz)

Tables: schedule_job, schedule_job_log, plus standard qrtz_* tables.

  • ScheduleConfig: Quartz SchedulerFactoryBean configuration
  • ScheduleJob entity: bean class, cron expression, params, status (PAUSE/NORMAL)
  • ScheduleUtils: Create/update/delete/pause/resume Quartz triggers
  • JobCommandLineRunner: On startup, restores all NORMAL-status jobs from DB
  • ITask interface: run(String params) method -- all job classes implement this
  • Concurrency control via @DisallowConcurrentExecution

Database

Schema: system-admin/db/weather_data_system.sql

Core Tables

Table Purpose
sys_user, sys_role, sys_menu, sys_dept RBAC
sys_role_user, sys_role_menu, sys_role_data_scope RBAC associations
sys_user_token Shiro auth tokens
sys_dict_type, sys_dict_data Dictionary system
sys_params Key-value system parameters
sys_alert Alert/notification records
weather_station Weather station registry
weather_daily_data Daily meteorological observations
weather_file_scan_record File tracking (receive -> display -> archive)
sys_region Geographic region tree (province/city/county)
schedule_job, schedule_job_log Quartz job definitions and execution history
qrtz_* Quartz internal scheduler tables
sys_log_operation, sys_log_login, sys_log_error Audit logs
sys_oss Cloud storage object records