diff --git a/pom.xml b/pom.xml index 3ac5aa1..86420a7 100644 --- a/pom.xml +++ b/pom.xml @@ -82,6 +82,13 @@ 3.5.9 + + + com.baomidou + mybatis-plus-jsqlparser + 3.5.9 + + org.apache.shiro diff --git a/src/main/java/com/label/common/config/MybatisPlusConfig.java b/src/main/java/com/label/common/config/MybatisPlusConfig.java new file mode 100644 index 0000000..2b52882 --- /dev/null +++ b/src/main/java/com/label/common/config/MybatisPlusConfig.java @@ -0,0 +1,57 @@ +package com.label.common.config; + +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import com.label.common.context.CompanyContext; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.NullValue; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Arrays; +import java.util.List; + +@Configuration +public class MybatisPlusConfig { + + // Tables that do NOT need tenant isolation (either global or tenant root tables) + private static final List IGNORED_TABLES = Arrays.asList( + "sys_company", // the tenant root table itself + "sys_config" // has company_id=NULL for global defaults; service handles this manually + ); + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + + // 1. Tenant isolation - auto-injects WHERE company_id = ? + interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() { + @Override + public Expression getTenantId() { + Long companyId = CompanyContext.get(); + if (companyId == null) { + return new NullValue(); + } + return new LongValue(companyId); + } + + @Override + public String getTenantIdColumn() { + return "company_id"; + } + + @Override + public boolean ignoreTable(String tableName) { + return IGNORED_TABLES.contains(tableName); + } + })); + + // 2. Pagination interceptor (required for MyBatis Plus Page queries) + interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); + + return interceptor; + } +} diff --git a/src/main/java/com/label/common/statemachine/StateValidator.java b/src/main/java/com/label/common/statemachine/StateValidator.java new file mode 100644 index 0000000..cf4385b --- /dev/null +++ b/src/main/java/com/label/common/statemachine/StateValidator.java @@ -0,0 +1,36 @@ +package com.label.common.statemachine; + +import com.label.common.exception.BusinessException; +import org.springframework.http.HttpStatus; + +import java.util.Map; +import java.util.Set; + +/** + * Generic state machine validator. + * Validates state transitions against a predefined transitions map. + */ +public final class StateValidator { + + private StateValidator() {} + + /** + * Assert that a state transition from {@code current} to {@code next} is valid. + * + * @param transitions the allowed transitions map + * @param current the current state + * @param next the desired next state + * @param the state type (enum) + * @throws BusinessException with code INVALID_STATE_TRANSITION if transition not allowed + */ + public static void assertTransition(Map> transitions, S current, S next) { + Set allowed = transitions.get(current); + if (allowed == null || !allowed.contains(next)) { + throw new BusinessException( + "INVALID_STATE_TRANSITION", + String.format("不允许的状态转换: %s → %s", current, next), + HttpStatus.CONFLICT + ); + } + } +}