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
tokenheader/param ->Oauth2Filterextracts it ->Oauth2Realmvalidates againstsys_user_tokentable -> returnsUserDetail(user + dept scope + permissions) - Public paths (no auth):
/login,/captcha,/druid/**,/doc.html,/swagger/**,/v3/api-docs/**,/favicon.ico - Password hashing: Custom
BCryptPasswordEncoderwithPasswordUtils(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:
- Directory layout:
receive/<deptName>/,display/<deptName>/,archive/<deptName>/ - Detection: WatchService detects
ENTRY_CREATEandENTRY_MODIFYevents - Wait:
waitForFileReady()polls file size stability + file lock to ensure write completion - Dedup: MD5 hash check against
weather_file_scan_recordtable - Parse:
FileNameParserextracts region, category, period from filename - Store: Record inserted; file copied to
display/; old version moved toarchive/ - Root files: Files in
receive/root (no dept subdir) are classified as "model forecast" withdeptId = 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:
- Save MultipartFile to temp file
- Submit async task (
CompletableFuture), returns taskId immediately - First pass:
EasyExcel.read()with count listener to get total rows - Second pass:
WeatherDataListenerreads rows in batches, callsinsertBatch() insertBatch()resolves station-to-dept mapping, fills audit fields, usesinsertBatchMultiRow()(custom MySQL multi-row INSERT)- Clears weather summarize Redis cache on completion
- 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:
SysAlertEntityinsys_alerttable - Real-time push:
SseAlertServicemanages active SSE connections (CopyOnWriteArraySet<SseEmitter>), broadcasts on Spring events:AlertCreatedEvent-> SSE eventalertAlertWithdrawnEvent-> SSE eventalert-withdrawnAlertDeletedEvent-> SSE eventalert-deleted
- External sources:
AlertSourcePollingTask(Quartz) polls external services;AlertSourceCollectorgathers results
Job Scheduling (Quartz)
Tables: schedule_job, schedule_job_log, plus standard qrtz_* tables.
ScheduleConfig: QuartzSchedulerFactoryBeanconfigurationScheduleJobentity: bean class, cron expression, params, status (PAUSE/NORMAL)ScheduleUtils: Create/update/delete/pause/resume Quartz triggersJobCommandLineRunner: On startup, restores all NORMAL-status jobs from DBITaskinterface: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 |