1、security模块ExpressionUrlAuthorizationConfigurer改为AuthorizeHttpRequestsConfigurer
2、全局registry.antMatchers改为registry.requestMatchers
3、增加积木报表
| | |
| | | - id: report-jimu # 路由的编号(积木报表) |
| | | uri: grayLb://report-server |
| | | predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 |
| | | - Path=/jmreport/** |
| | | - Path=/jmreport/**, /drag/** |
| | | ## statistics-server 服务 |
| | | - id: statistics-admin-api # 路由的编号 |
| | | uri: grayLb://statistics-server |
| | |
| | | - name: model-server |
| | | service-name: model-server |
| | | url: /admin-api/model/v3/api-docs |
| | | - name: report-server |
| | | service-name: report-server |
| | | url: /admin-api/report/v3/api-docs |
| | | --- #################### 平台相关配置 #################### |
| | | |
| | | iailab: |
| | |
| | | import org.springframework.core.Ordered; |
| | | import org.springframework.security.config.Customizer; |
| | | import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
| | | import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; |
| | | import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; |
| | | |
| | | import javax.annotation.Resource; |
| | |
| | | * @author iailab |
| | | */ |
| | | public abstract class AuthorizeRequestsCustomizer |
| | | implements Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry>, Ordered { |
| | | implements Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry>, Ordered { |
| | | |
| | | @Resource |
| | | private WebProperties webProperties; |
| | |
| | | // 设置每个请求的权限 |
| | | httpSecurity |
| | | // ①:全局共享规则 |
| | | .authorizeRequests() |
| | | // 1.1 静态资源,可匿名访问 |
| | | .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() |
| | | // 1.2 设置 @PermitAll 无需认证 |
| | | .antMatchers(HttpMethod.GET, permitAllUrls.get(HttpMethod.GET).toArray(new String[0])).permitAll() |
| | | .antMatchers(HttpMethod.POST, permitAllUrls.get(HttpMethod.POST).toArray(new String[0])).permitAll() |
| | | .antMatchers(HttpMethod.PUT, permitAllUrls.get(HttpMethod.PUT).toArray(new String[0])).permitAll() |
| | | .antMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll() |
| | | // 1.3 基于 iailab.security.permit-all-urls 无需认证 |
| | | .antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll() |
| | | // 1.4 设置 App API 无需认证 |
| | | .antMatchers(buildAppApi("/**")).permitAll() |
| | | // 1.5 验证码captcha 允许匿名访问 |
| | | .antMatchers("/captcha/get", "/captcha/check").permitAll() |
| | | .authorizeHttpRequests(c -> c |
| | | // 1.1 静态资源,可匿名访问 |
| | | .requestMatchers(HttpMethod.GET, "/*.html", "/*.html", "/*.css", "/*.js").permitAll() |
| | | // 1.2 设置 @PermitAll 无需认证 |
| | | .requestMatchers(HttpMethod.GET, permitAllUrls.get(HttpMethod.GET).toArray(new String[0])).permitAll() |
| | | .requestMatchers(HttpMethod.POST, permitAllUrls.get(HttpMethod.POST).toArray(new String[0])).permitAll() |
| | | .requestMatchers(HttpMethod.PUT, permitAllUrls.get(HttpMethod.PUT).toArray(new String[0])).permitAll() |
| | | .requestMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll() |
| | | .requestMatchers(HttpMethod.HEAD, permitAllUrls.get(HttpMethod.HEAD).toArray(new String[0])).permitAll() |
| | | .requestMatchers(HttpMethod.PATCH, permitAllUrls.get(HttpMethod.PATCH).toArray(new String[0])).permitAll() |
| | | // 1.3 基于 yudao.security.permit-all-urls 无需认证 |
| | | .requestMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll() |
| | | ) |
| | | // ②:每个项目的自定义规则 |
| | | .and().authorizeRequests(registry -> // 下面,循环设置自定义规则 |
| | | authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry))) |
| | | .authorizeHttpRequests(c -> authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(c))) |
| | | // ③:兜底规则,必须认证 |
| | | .authorizeRequests() |
| | | .anyRequest().authenticated(); |
| | | .authorizeHttpRequests(c -> c.anyRequest().authenticated()); |
| | | |
| | | // 添加 Token Filter |
| | | httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); |
| | |
| | | import com.iailab.framework.websocket.config.WebSocketProperties; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
| | | import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; |
| | | import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; |
| | | |
| | | /** |
| | | * WebSocket 的权限自定义 |
| | |
| | | private final WebSocketProperties webSocketProperties; |
| | | |
| | | @Override |
| | | public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) { |
| | | registry.antMatchers(webSocketProperties.getPath()).permitAll(); |
| | | public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) { |
| | | registry.requestMatchers(webSocketProperties.getPath()).permitAll(); |
| | | } |
| | | |
| | | } |
| | |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
| | | import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; |
| | | import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; |
| | | |
| | | /** |
| | | * Bpm 模块的 Security 配置 |
| | |
| | | return new AuthorizeRequestsCustomizer() { |
| | | |
| | | @Override |
| | | public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) { |
| | | public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) { |
| | | // TODO iailab:这个每个项目都需要重复配置,得捉摸有没通用的方案 |
| | | // Swagger 接口文档 |
| | | registry.antMatchers("/v3/api-docs/**").permitAll() // 元数据 |
| | | .antMatchers("/swagger-ui.html").permitAll(); // Swagger UI |
| | | registry.requestMatchers("/v3/api-docs/**").permitAll() // 元数据 |
| | | .requestMatchers("/swagger-ui.html").permitAll(); // Swagger UI |
| | | // Druid 监控 |
| | | registry.antMatchers("/druid/**").anonymous(); |
| | | registry.requestMatchers("/druid/**").anonymous(); |
| | | // Spring Boot Actuator 的安全配置 |
| | | registry.antMatchers("/actuator").anonymous() |
| | | .antMatchers("/actuator/**").anonymous(); |
| | | registry.requestMatchers("/actuator").anonymous() |
| | | .requestMatchers("/actuator/**").anonymous(); |
| | | } |
| | | |
| | | }; |
| | |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
| | | import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; |
| | | import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; |
| | | |
| | | /** |
| | | * System 模块的 Security 配置 |
| | |
| | | return new AuthorizeRequestsCustomizer() { |
| | | |
| | | @Override |
| | | public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) { |
| | | public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) { |
| | | // TODO iailab:这个每个项目都需要重复配置,得捉摸有没通用的方案 |
| | | // Swagger 接口文档 |
| | | registry.antMatchers("/v3/api-docs/**").permitAll() // 元数据 |
| | | .antMatchers("/swagger-ui.html").permitAll(); // Swagger UI |
| | | registry.requestMatchers("/v3/api-docs/**").permitAll() // 元数据 |
| | | .requestMatchers("/swagger-ui.html").permitAll(); // Swagger UI |
| | | // Druid 监控 |
| | | registry.antMatchers("/druid/**").anonymous(); |
| | | registry.requestMatchers("/druid/**").anonymous(); |
| | | // Spring Boot Actuator 的安全配置 |
| | | registry.antMatchers("/actuator").anonymous() |
| | | .antMatchers("/actuator/**").anonymous(); |
| | | registry.requestMatchers("/actuator").anonymous() |
| | | .requestMatchers("/actuator/**").anonymous(); |
| | | // RPC 服务的安全配置 |
| | | registry.antMatchers(ApiConstants.PREFIX + "/**").permitAll(); |
| | | registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll(); |
| | | } |
| | | |
| | | }; |
| | |
| | | </dependency> |
| | | |
| | | <!-- Job 定时任务相关 --> |
| | | <dependency> |
| | | <groupId>com.iailab</groupId> |
| | | <artifactId>iailab-common-job</artifactId> |
| | | </dependency> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>com.iailab</groupId>--> |
| | | <!-- <artifactId>iailab-common-job</artifactId>--> |
| | | <!-- </dependency>--> |
| | | |
| | | <!-- 消息队列相关 --> |
| | | <!-- <dependency>--> |
| | |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
| | | import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; |
| | | import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; |
| | | |
| | | /** |
| | | * Infra 模块的 Security 配置 |
| | |
| | | return new AuthorizeRequestsCustomizer() { |
| | | |
| | | @Override |
| | | public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) { |
| | | public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) { |
| | | // Swagger 接口文档 |
| | | registry.antMatchers("/v3/api-docs/**").permitAll() |
| | | .antMatchers("/webjars/**").permitAll() |
| | | .antMatchers("/swagger-ui").permitAll() |
| | | .antMatchers("/swagger-ui/**").permitAll(); |
| | | registry.requestMatchers("/v3/api-docs/**").permitAll() |
| | | .requestMatchers("/webjars/**").permitAll() |
| | | .requestMatchers("/swagger-ui").permitAll() |
| | | .requestMatchers("/swagger-ui/**").permitAll(); |
| | | // Spring Boot Actuator 的安全配置 |
| | | registry.antMatchers("/actuator").anonymous() |
| | | .antMatchers("/actuator/**").anonymous(); |
| | | registry.requestMatchers("/actuator").permitAll() |
| | | .requestMatchers("/actuator/**").permitAll(); |
| | | // Druid 监控 |
| | | registry.antMatchers("/druid/**").anonymous(); |
| | | registry.requestMatchers("/druid/**").permitAll(); |
| | | // Spring Boot Admin Server 的安全配置 |
| | | registry.antMatchers(adminSeverContextPath).anonymous() |
| | | .antMatchers(adminSeverContextPath + "/**").anonymous(); |
| | | registry.requestMatchers(adminSeverContextPath).permitAll() |
| | | .requestMatchers(adminSeverContextPath + "/**").permitAll(); |
| | | // 文件读取 |
| | | registry.antMatchers(buildAdminApi("/infra/file/*/get/**")).permitAll(); |
| | | registry.requestMatchers(buildAdminApi("/infra/file/*/get/**")).permitAll(); |
| | | |
| | | // TODO iailab:这个每个项目都需要重复配置,得捉摸有没通用的方案 |
| | | // RPC 服务的安全配置 |
| | | registry.antMatchers(ApiConstants.PREFIX + "/**").permitAll(); |
| | | registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll(); |
| | | } |
| | | |
| | | }; |
| | |
| | | package com.iailab.module.infra.job.demo; |
| | | |
| | | import com.iailab.framework.tenant.core.job.TenantJob; |
| | | import com.xxl.job.core.handler.annotation.XxlJob; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.util.Date; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | @Component |
| | | public class DemoJob { |
| | | |
| | | private Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | private final AtomicInteger counts = new AtomicInteger(); |
| | | |
| | | private static final Object lock = new Object(); |
| | | |
| | | |
| | | @XxlJob("demoJob") |
| | | // @TenantJob |
| | | public void execute() { |
| | | synchronized (lock) { |
| | | logger.info("[execute][定时第 ({}) 次执行]", counts.incrementAndGet()); |
| | | System.out.println(new Date() + ": 我是基础设施定时任务"); |
| | | } |
| | | } |
| | | |
| | | } |
| | | //package com.iailab.module.infra.job.demo; |
| | | // |
| | | //import com.iailab.framework.tenant.core.job.TenantJob; |
| | | //import com.xxl.job.core.handler.annotation.XxlJob; |
| | | //import org.slf4j.Logger; |
| | | //import org.slf4j.LoggerFactory; |
| | | //import org.springframework.stereotype.Component; |
| | | // |
| | | //import java.util.Date; |
| | | //import java.util.concurrent.atomic.AtomicInteger; |
| | | // |
| | | //@Component |
| | | //public class DemoJob { |
| | | // |
| | | // private Logger logger = LoggerFactory.getLogger(getClass()); |
| | | // |
| | | // private final AtomicInteger counts = new AtomicInteger(); |
| | | // |
| | | // private static final Object lock = new Object(); |
| | | // |
| | | // |
| | | // @XxlJob("demoJob") |
| | | //// @TenantJob |
| | | // public void execute() { |
| | | // synchronized (lock) { |
| | | // logger.info("[execute][定时第 ({}) 次执行]", counts.incrementAndGet()); |
| | | // System.out.println(new Date() + ": 我是基础设施定时任务"); |
| | | // } |
| | | // } |
| | | // |
| | | //} |
| | |
| | | package com.iailab.module.infra.job.logger; |
| | | |
| | | import com.iailab.framework.tenant.core.aop.TenantIgnore; |
| | | import com.iailab.module.infra.service.logger.ApiAccessLogService; |
| | | import com.xxl.job.core.handler.annotation.XxlJob; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.annotation.Resource; |
| | | |
| | | /** |
| | | * 物理删除 N 天前的访问日志的 Job |
| | | * |
| | | * @author j-sentinel |
| | | */ |
| | | @Component |
| | | @Slf4j |
| | | public class AccessLogCleanJob { |
| | | |
| | | @Resource |
| | | private ApiAccessLogService apiAccessLogService; |
| | | |
| | | /** |
| | | * 清理超过(14)天的日志 |
| | | */ |
| | | private static final Integer JOB_CLEAN_RETAIN_DAY = 14; |
| | | |
| | | /** |
| | | * 每次删除间隔的条数,如果值太高可能会造成数据库的压力过大 |
| | | */ |
| | | private static final Integer DELETE_LIMIT = 100; |
| | | |
| | | @XxlJob("accessLogCleanJob") |
| | | @TenantIgnore |
| | | public void execute() { |
| | | Integer count = apiAccessLogService.cleanAccessLog(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT); |
| | | log.info("[execute][定时执行清理访问日志数量 ({}) 个]", count); |
| | | } |
| | | |
| | | } |
| | | //package com.iailab.module.infra.job.logger; |
| | | // |
| | | //import com.iailab.framework.tenant.core.aop.TenantIgnore; |
| | | //import com.iailab.module.infra.service.logger.ApiAccessLogService; |
| | | //import com.xxl.job.core.handler.annotation.XxlJob; |
| | | //import lombok.extern.slf4j.Slf4j; |
| | | //import org.springframework.stereotype.Component; |
| | | // |
| | | //import javax.annotation.Resource; |
| | | // |
| | | ///** |
| | | // * 物理删除 N 天前的访问日志的 Job |
| | | // * |
| | | // * @author j-sentinel |
| | | // */ |
| | | //@Component |
| | | //@Slf4j |
| | | //public class AccessLogCleanJob { |
| | | // |
| | | // @Resource |
| | | // private ApiAccessLogService apiAccessLogService; |
| | | // |
| | | // /** |
| | | // * 清理超过(14)天的日志 |
| | | // */ |
| | | // private static final Integer JOB_CLEAN_RETAIN_DAY = 14; |
| | | // |
| | | // /** |
| | | // * 每次删除间隔的条数,如果值太高可能会造成数据库的压力过大 |
| | | // */ |
| | | // private static final Integer DELETE_LIMIT = 100; |
| | | // |
| | | // @XxlJob("accessLogCleanJob") |
| | | // @TenantIgnore |
| | | // public void execute() { |
| | | // Integer count = apiAccessLogService.cleanAccessLog(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT); |
| | | // log.info("[execute][定时执行清理访问日志数量 ({}) 个]", count); |
| | | // } |
| | | // |
| | | //} |
| | |
| | | package com.iailab.module.infra.job.logger; |
| | | |
| | | import com.iailab.framework.tenant.core.aop.TenantIgnore; |
| | | import com.iailab.module.infra.service.logger.ApiErrorLogService; |
| | | import com.xxl.job.core.handler.annotation.XxlJob; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.annotation.Resource; |
| | | |
| | | /** |
| | | * 物理删除 N 天前的错误日志的 Job |
| | | * |
| | | * @author j-sentinel |
| | | */ |
| | | @Slf4j |
| | | @Component |
| | | public class ErrorLogCleanJob { |
| | | |
| | | @Resource |
| | | private ApiErrorLogService apiErrorLogService; |
| | | |
| | | /** |
| | | * 清理超过(14)天的日志 |
| | | */ |
| | | private static final Integer JOB_CLEAN_RETAIN_DAY = 14; |
| | | |
| | | /** |
| | | * 每次删除间隔的条数,如果值太高可能会造成数据库的压力过大 |
| | | */ |
| | | private static final Integer DELETE_LIMIT = 100; |
| | | |
| | | @XxlJob("errorLogCleanJob") |
| | | @TenantIgnore |
| | | public void execute() { |
| | | Integer count = apiErrorLogService.cleanErrorLog(JOB_CLEAN_RETAIN_DAY,DELETE_LIMIT); |
| | | log.info("[execute][定时执行清理错误日志数量 ({}) 个]", count); |
| | | } |
| | | |
| | | } |
| | | //package com.iailab.module.infra.job.logger; |
| | | // |
| | | //import com.iailab.framework.tenant.core.aop.TenantIgnore; |
| | | //import com.iailab.module.infra.service.logger.ApiErrorLogService; |
| | | //import com.xxl.job.core.handler.annotation.XxlJob; |
| | | //import lombok.extern.slf4j.Slf4j; |
| | | //import org.springframework.stereotype.Component; |
| | | // |
| | | //import javax.annotation.Resource; |
| | | // |
| | | ///** |
| | | // * 物理删除 N 天前的错误日志的 Job |
| | | // * |
| | | // * @author j-sentinel |
| | | // */ |
| | | //@Slf4j |
| | | //@Component |
| | | //public class ErrorLogCleanJob { |
| | | // |
| | | // @Resource |
| | | // private ApiErrorLogService apiErrorLogService; |
| | | // |
| | | // /** |
| | | // * 清理超过(14)天的日志 |
| | | // */ |
| | | // private static final Integer JOB_CLEAN_RETAIN_DAY = 14; |
| | | // |
| | | // /** |
| | | // * 每次删除间隔的条数,如果值太高可能会造成数据库的压力过大 |
| | | // */ |
| | | // private static final Integer DELETE_LIMIT = 100; |
| | | // |
| | | // @XxlJob("errorLogCleanJob") |
| | | // @TenantIgnore |
| | | // public void execute() { |
| | | // Integer count = apiErrorLogService.cleanErrorLog(JOB_CLEAN_RETAIN_DAY,DELETE_LIMIT); |
| | | // log.info("[execute][定时执行清理错误日志数量 ({}) 个]", count); |
| | | // } |
| | | // |
| | | //} |
| | |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
| | | import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; |
| | | import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; |
| | | |
| | | /** |
| | | * System 模块的 Security 配置 |
| | |
| | | return new AuthorizeRequestsCustomizer() { |
| | | |
| | | @Override |
| | | public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) { |
| | | public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) { |
| | | // TODO iailab:这个每个项目都需要重复配置,得捉摸有没通用的方案 |
| | | // Swagger 接口文档 |
| | | registry.antMatchers("/v3/api-docs/**").permitAll() // 元数据 |
| | | .antMatchers("/swagger-ui.html").permitAll(); // Swagger UI |
| | | registry.requestMatchers("/v3/api-docs/**").permitAll() // 元数据 |
| | | .requestMatchers("/swagger-ui.html").permitAll(); // Swagger UI |
| | | // Druid 监控 |
| | | registry.antMatchers("/druid/**").anonymous(); |
| | | registry.requestMatchers("/druid/**").anonymous(); |
| | | // Spring Boot Actuator 的安全配置 |
| | | registry.antMatchers("/actuator").anonymous() |
| | | .antMatchers("/actuator/**").anonymous(); |
| | | registry.requestMatchers("/actuator").anonymous() |
| | | .requestMatchers("/actuator/**").anonymous(); |
| | | |
| | | registry.antMatchers("/admin-api/model/pre/item/upload-model").anonymous(); |
| | | registry.requestMatchers("/admin-api/model/pre/item/upload-model").anonymous(); |
| | | // RPC 服务的安全配置 |
| | | registry.antMatchers(ApiConstants.PREFIX + "/**").permitAll(); |
| | | registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll(); |
| | | } |
| | | |
| | | }; |
| | |
| | | <groupId>org.jeecgframework.jimureport</groupId> |
| | | <artifactId>jimureport-spring-boot-starter</artifactId> |
| | | </dependency> |
| | | <!-- 积木仪表盘--> |
| | | <dependency> |
| | | <groupId>org.jeecgframework.jimureport</groupId> |
| | | <artifactId>jimureport-dashboard-spring-boot-starter</artifactId> |
| | | <exclusions> |
| | | <exclusion> |
| | | <artifactId>autopoi-web</artifactId> |
| | | <groupId>org.jeecgframework</groupId> |
| | | </exclusion> |
| | | <exclusion> |
| | | <groupId>org.jeecgframework.jimureport</groupId> |
| | | <artifactId>jimureport-spring-boot-starter</artifactId> |
| | | </exclusion> |
| | | <exclusion> |
| | | <groupId>com.github.jsqlparser</groupId> |
| | | <artifactId>jsqlparser</artifactId> |
| | | </exclusion> |
| | | </exclusions> |
| | | </dependency> |
| | | <!-- 单独依赖升级版本,解决低版本validator失败问题 --> |
| | | <dependency> |
| | | <groupId>xerces</groupId> |
| | |
| | | /** |
| | | * 项目的启动类 |
| | | * |
| | | * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 |
| | | * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 |
| | | * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 |
| | | * |
| | | * @author iailab |
| | | */ |
| | | @SpringBootApplication |
| | | public class ReportServerApplication { |
| | | |
| | | public static void main(String[] args) { |
| | | // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 |
| | | // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 |
| | | // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 |
| | | |
| | | SpringApplication.run(ReportServerApplication.class, args); |
| | | |
| | | // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 |
| | | // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 |
| | | // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | @Override |
| | | public String[] getRoles(String token) { |
| | | // 设置租户上下文。原因是:/jmreport/** 纯前端地址,不会走 buildLoginUserByToken 逻辑 |
| | | LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); |
| | | if (loginUser == null) { |
| | | return null; |
| | | } |
| | | TenantContextHolder.setTenantId(loginUser.getTenantId()); |
| | | |
| | | // 参见文档 https://help.jeecg.com/jimureport/prodSafe.html 文档 |
| | | // 适配:如果是本系统的管理员,则转换成 jimu 报表的管理员 |
| | | Long userId = SecurityFrameworkUtils.getLoginUserId(); |
| | |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
| | | import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; |
| | | import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; |
| | | |
| | | /** |
| | | * Report 模块的 Security 配置 |
| | |
| | | return new AuthorizeRequestsCustomizer() { |
| | | |
| | | @Override |
| | | public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) { |
| | | public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) { |
| | | // Swagger 接口文档 |
| | | registry.antMatchers("/v3/api-docs/**").permitAll() // 元数据 |
| | | .antMatchers("/swagger-ui.html").permitAll(); // Swagger UI |
| | | registry.requestMatchers("/v3/api-docs/**").permitAll() |
| | | .requestMatchers("/webjars/**").permitAll() |
| | | .requestMatchers("/swagger-ui").permitAll() |
| | | .requestMatchers("/swagger-ui/**").permitAll(); |
| | | // Spring Boot Actuator 的安全配置 |
| | | registry.antMatchers("/actuator").anonymous() |
| | | .antMatchers("/actuator/**").anonymous(); |
| | | registry.requestMatchers("/actuator").permitAll() |
| | | .requestMatchers("/actuator/**").permitAll(); |
| | | // Druid 监控 |
| | | registry.antMatchers("/druid/**").anonymous(); |
| | | registry.requestMatchers("/druid/**").permitAll(); |
| | | // 积木报表 |
| | | registry.antMatchers("/jmreport/**").permitAll(); |
| | | registry.requestMatchers("/jmreport/**").permitAll(); |
| | | // 积木仪表盘排除 |
| | | registry.requestMatchers("/drag/**").permitAll(); |
| | | } |
| | | |
| | | }; |
| | | } |
| | | |
| | | } |
| | |
| | | primary: master |
| | | datasource: |
| | | master: |
| | | url: jdbc:mysql://127.0.0.1:3306/iailab_plat_system?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 |
| | | url: jdbc:mysql://172.16.8.100:3306/iailab_jmreport?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 |
| | | username: root |
| | | password: 123456 |
| | | slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 |
| | | lazy: true # 开启懒加载,保证启动速度 |
| | | url: jdbc:mysql://127.0.0.1:3306/iailab-plat?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 |
| | | url: jdbc:mysql://127.0.0.1:3306/jimureport?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 |
| | | username: root |
| | | password: 123456 |
| | | |
| | |
| | | port: 6379 # 端口 |
| | | database: 1 # 数据库索引 |
| | | password: 123456 # 密码,建议生产环境开启 |
| | | |
| | | --- #################### MQ 消息队列相关配置 #################### |
| | | |
| | | --- #################### 定时任务相关配置 #################### |
| | | |
| | | --- #################### 服务保障相关配置 #################### |
| | | |
| | | # Lock4j 配置项 |
| | | lock4j: |
| | |
| | | |
| | | # 平台配置项,设置当前项目所有自定义的配置 |
| | | iailab: |
| | | xss: |
| | | enable: false |
| | | exclude-urls: # 如下两个 url,仅仅是为了演示,去掉配置也没关系 |
| | | - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求 |
| | | - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求 |
| | | demo: true # 开启演示模式 |
| | | demo: false # 开启演示模式 |
| | |
| | | multipart: |
| | | max-file-size: 16MB # 单个文件大小 |
| | | max-request-size: 32MB # 设置总上传的文件大小 |
| | | mvc: |
| | | pathmatch: |
| | | matching-strategy: ANT_PATH_MATCHER # 解决 SpringFox 与 SpringBoot 2.6.x 不兼容的问题,参见 SpringFoxHandlerProviderBeanPostProcessor 类 |
| | | |
| | | # Jackson 配置项 |
| | | jackson: |
| | |
| | | path: /v3/api-docs |
| | | swagger-ui: |
| | | enabled: true # 2.1 是否开启 Swagger 文档的官方 UI 界面 |
| | | path: /swagger-ui.html |
| | | path: /swagger-ui |
| | | default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档 |
| | | |
| | | knife4j: |
| | |
| | | # VO 转换(数据翻译)相关 |
| | | easy-trans: |
| | | is-enable-global: true # 启用全局翻译(拦截所有 SpringMVC ResponseBody 进行自动翻译 )。如果对于性能要求很高可关闭此配置,或通过 @IgnoreTrans 忽略某个接口 |
| | | is-enable-cloud: false # 禁用 TransType.RPC 微服务模式 |
| | | |
| | | --- #################### RPC 远程调用相关配置 #################### |
| | | |
| | | --- #################### MQ 消息队列相关配置 #################### |
| | | |
| | | --- #################### 定时任务相关配置 #################### |
| | | |
| | | # 积木报表配置 |
| | | jeecg: |
| | | jmreport: |
| | | saas-mode: tenant |
| | | |
| | | --- #################### 平台相关配置 #################### |
| | | |
| | |
| | | description: 提供管理员管理的所有功能 |
| | | version: ${iailab.info.version} |
| | | tenant: # 多租户相关配置项 |
| | | enable: false |
| | | enable: true |
| | | |
| | | debug: false |
| | | jeecg: |
| | | uploadType: local |
| | | path: |
| | | upload: D:/DLUT/IailabPlat |
| | | #大屏报表参数设置 |
| | | jmreport: |
| | | #多租户模式,默认值为空(created:按照创建人隔离、tenant:按照租户隔离) (v1.6.2+ 新增) |
| | | saasMode: tenant |
| | | # 平台上线安全配置(v1.6.2+ 新增) |
| | | firewall: |
| | | # 数据源安全 (开启后,不允许使用平台数据源、SQL解析加签并且不允许查询数据库) |
| | | dataSourceSafe: false |
| | | # 低代码开发模式(dev:开发模式,prod:发布模式—关闭在线报表设计功能,分配角色admin、lowdeveloper可以放开限制) |
| | | lowCodeMode: dev |
| | | |
| | | minidao : |
| | | base-package: org.jeecg.modules.jmreport.desreport.dao*, org.jeecg.modules.drag.dao* |
| | | |
| | | debug: true |
| | |
| | | Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId)); |
| | | List<MenuDO> menuList = menuService.getMenuList(menuIds); |
| | | menuList = menuService.filterDisableMenus(menuList); |
| | | menuList = menuService.filterMenus(menuList, "system"); |
| | | |
| | | // 2. 拼接结果返回 |
| | | return success(AuthConvert.INSTANCE.convert(user, roles, menuList)); |
| | |
| | | * |
| | | * 注意,默认需要传递 client_id + client_secret 参数 |
| | | */ |
| | | @PostMapping("/fast/token") |
| | | @PermitAll |
| | | @Operation(summary = "脚手架获得访问令牌", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用") |
| | | @Parameters({ |
| | | @Parameter(name = "grant_type", required = true, description = "授权类型", example = "code"), |
| | | @Parameter(name = "code", description = "授权范围", example = "userinfo.read"), |
| | | @Parameter(name = "redirect_uri", description = "重定向 URI", example = "https://www.iocoder.cn"), |
| | | @Parameter(name = "state", description = "状态", example = "1"), |
| | | @Parameter(name = "username", example = "tudou"), |
| | | @Parameter(name = "password", example = "cai"), // 多个使用空格分隔 |
| | | @Parameter(name = "scope", example = "user_info"), |
| | | @Parameter(name = "refresh_token", example = "123424233"), |
| | | }) |
| | | public CommonResult<OAuth2OpenAccessTokenRespVO> FastAccessToken(HttpServletRequest request, |
| | | @RequestParam("grant_type") String grantType, |
| | | @RequestParam(value = "code", required = false) String code, // 授权码模式 |
| | | @RequestParam(value = "redirect_uri", required = false) String redirectUri, // 授权码模式 |
| | | @RequestParam(value = "state", required = false) String state, // 授权码模式 |
| | | @RequestParam(value = "username", required = false) String username, // 密码模式 |
| | | @RequestParam(value = "password", required = false) String password, // 密码模式 |
| | | @RequestParam(value = "scope", required = false) String scope, // 密码模式 |
| | | @RequestParam(value = "refresh_token", required = false) String refreshToken) { // 刷新模式 |
| | | OAuth2AccessTokenDO accessTokenDO = getAccessToken(request, grantType, code, redirectUri, state, username, password, scope, refreshToken); |
| | | Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查 |
| | | return success(OAuth2OpenConvert.INSTANCE.convert(accessTokenDO)); |
| | | } |
| | | |
| | | /** |
| | | * 对应 Spring Security OAuth 的 TokenEndpoint 类的 postAccessToken 方法 |
| | | * |
| | | * 外部平台专用授权方式 |
| | | * |
| | | * 注意,默认需要传递 client_id + client_secret 参数 |
| | | */ |
| | | @PostMapping("/token") |
| | | @PermitAll |
| | | @Operation(summary = "获得访问令牌", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用") |
| | | @Operation(summary = "外部平台获得访问令牌", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用") |
| | | @Parameters({ |
| | | @Parameter(name = "grant_type", required = true, description = "授权类型", example = "code"), |
| | | @Parameter(name = "code", description = "授权码", example = "asdfasdfasdf"), |
| | |
| | | @RequestParam(value = "password", required = false) String password, // 密码模式 |
| | | @RequestParam(value = "scope", required = false) String scope, // 密码模式 |
| | | @RequestParam(value = "refresh_token", required = false) String refreshToken) { // 刷新模式 |
| | | OAuth2AccessTokenDO accessTokenDO = getAccessToken(request, grantType, code, redirectUri, state, username, password, scope, refreshToken); |
| | | Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查 |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("access_token", accessTokenDO.getAccessToken()); |
| | | map.put("refresh_token", accessTokenDO.getRefreshToken()); |
| | | map.put("expires_time", LocalDateTimeUtil.toEpochMilli(accessTokenDO.getExpiresTime()) / 1000L); |
| | | map.put("client_id", accessTokenDO.getClientId()); |
| | | return map; |
| | | } |
| | | |
| | | private OAuth2AccessTokenDO getAccessToken(HttpServletRequest request, String grantType, String code, String redirectUri, String state, String username, String password, String scope, String refreshToken) { |
| | | List<String> scopes = OAuth2Utils.buildScopes(scope); |
| | | // 1.1 校验授权类型 |
| | | OAuth2GrantTypeEnum grantTypeEnum = OAuth2GrantTypeEnum.getByGrantType(grantType); |
| | |
| | | throw new IllegalArgumentException("未知授权类型:" + grantType); |
| | | } |
| | | Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查 |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("access_token", accessTokenDO.getAccessToken()); |
| | | map.put("refresh_token", accessTokenDO.getRefreshToken()); |
| | | map.put("expires_time", LocalDateTimeUtil.toEpochMilli(accessTokenDO.getExpiresTime()) / 1000L); |
| | | map.put("client_id", accessTokenDO.getClientId()); |
| | | return map; |
| | | return accessTokenDO; |
| | | } |
| | | |
| | | @DeleteMapping("/token") |
| | |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | import static com.iailab.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| | | |
| | |
| | | @Schema(description = "状态", example = "1") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "套餐图标", example = "http://localhost/xxx") |
| | | private String icon; |
| | | |
| | | @Schema(description = "套餐标签", example = "模型管理") |
| | | private List<String> labels; |
| | | |
| | | @Schema(description = "描述", example = "好") |
| | | private String description; |
| | | |
| | | @Schema(description = "备注", example = "好") |
| | | private String remark; |
| | | |
| | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotEmpty; |
| | | import javax.validation.constraints.NotNull; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | @Schema(description = "管理后台 - 租户套餐 Response VO") |
| | |
| | | @Schema(description = "套餐名", requiredMode = Schema.RequiredMode.REQUIRED, example = "VIP") |
| | | private String name; |
| | | |
| | | @Schema(description = "套餐图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://localhost/xxx") |
| | | private String icon; |
| | | |
| | | @Schema(description = "套餐标签", example = "模型管理") |
| | | private List<String> labels; |
| | | |
| | | @Schema(description = "描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "好") |
| | | private String description; |
| | | |
| | | @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Integer status; |
| | | |
| | |
| | | |
| | | import javax.validation.constraints.NotEmpty; |
| | | import javax.validation.constraints.NotNull; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | @Schema(description = "管理后台 - 租户套餐创建/修改 Request VO") |
| | |
| | | @NotEmpty(message = "套餐名不能为空") |
| | | private String name; |
| | | |
| | | @Schema(description = "套餐图标", example = "http://localhost/xxx") |
| | | @NotEmpty(message = "套餐图标不能为空") |
| | | private String icon; |
| | | |
| | | @Schema(description = "套餐标签", example = "模型管理") |
| | | private List<String> labels; |
| | | |
| | | @Schema(description = "描述", example = "好") |
| | | @NotNull(message = "描述不能为空") |
| | | private String description; |
| | | |
| | | @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "状态不能为空") |
| | | @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") |
| | |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.*; |
| | | |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | /** |
| | |
| | | */ |
| | | private Integer status; |
| | | /** |
| | | * 套餐图标 |
| | | */ |
| | | private String icon; |
| | | /** |
| | | * 套餐标签 |
| | | */ |
| | | @TableField(typeHandler = JacksonTypeHandler.class) |
| | | private List<String> labels; |
| | | /** |
| | | * 套餐介绍 |
| | | */ |
| | | private String description; |
| | | /** |
| | | * 备注 |
| | | */ |
| | | private String remark; |
| | |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<AppDO>() |
| | | .likeIfPresent(AppDO::getAppCode, reqVO.getAppCode()) |
| | | .likeIfPresent(AppDO::getAppName, reqVO.getAppName()) |
| | | .orderByDesc(AppDO::getType) |
| | | .orderByDesc(AppDO::getId)); |
| | | } |
| | | } |
| | |
| | | .eqIfPresent(MenuDO::getStatus, reqVO.getStatus())); |
| | | } |
| | | |
| | | default List<MenuDO> selectAppMenuList(Long tenantId, MenuListReqVO reqVO) { |
| | | default List<MenuDO> selectAppMenuList(MenuListReqVO reqVO) { |
| | | return selectList(new LambdaQueryWrapperX<MenuDO>() |
| | | .likeIfPresent(MenuDO::getName, reqVO.getName()) |
| | | .eqIfPresent(MenuDO::getStatus, reqVO.getStatus()) |
| | | .eq(MenuDO::getTenantId, tenantId)); |
| | | .eqIfPresent(MenuDO::getStatus, reqVO.getStatus())); |
| | | } |
| | | |
| | | default List<MenuDO> selectListByPermission(String permission) { |
| | |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
| | | import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; |
| | | import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; |
| | | |
| | | /** |
| | | * System 模块的 Security 配置 |
| | |
| | | return new AuthorizeRequestsCustomizer() { |
| | | |
| | | @Override |
| | | public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) { |
| | | public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) { |
| | | // TODO iailab:这个每个项目都需要重复配置,得捉摸有没通用的方案 |
| | | // Swagger 接口文档 |
| | | registry.antMatchers("/v3/api-docs/**").permitAll() // 元数据 |
| | | .antMatchers("/swagger-ui.html").permitAll(); // Swagger UI |
| | | registry.requestMatchers("/v3/api-docs/**").permitAll() |
| | | .requestMatchers("/webjars/**").permitAll() |
| | | .requestMatchers("/swagger-ui").permitAll() |
| | | .requestMatchers("/swagger-ui/**").permitAll(); |
| | | // Druid 监控 |
| | | registry.antMatchers("/druid/**").anonymous(); |
| | | registry.requestMatchers("/druid/**").permitAll(); |
| | | // Spring Boot Actuator 的安全配置 |
| | | registry.antMatchers("/actuator").anonymous() |
| | | .antMatchers("/actuator/**").anonymous(); |
| | | registry.requestMatchers("/actuator").permitAll() |
| | | .requestMatchers("/actuator/**").permitAll(); |
| | | // RPC 服务的安全配置 |
| | | registry.antMatchers(ApiConstants.PREFIX + "/**").permitAll(); |
| | | registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll(); |
| | | } |
| | | |
| | | }; |
| | |
| | | package com.iailab.module.system.job.demo; |
| | | |
| | | import com.iailab.framework.tenant.core.job.TenantJob; |
| | | import com.xxl.job.core.handler.annotation.XxlJob; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.util.Date; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | @Component |
| | | public class DemoJob { |
| | | |
| | | private Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | private final AtomicInteger counts = new AtomicInteger(); |
| | | |
| | | private static final Object lock = new Object(); |
| | | |
| | | |
| | | @XxlJob("demoJob") |
| | | @TenantJob |
| | | public void execute() { |
| | | synchronized (lock) { |
| | | logger.info("[execute][定时第 ({}) 次执行]", counts.incrementAndGet()); |
| | | System.out.println(new Date() + ": 我是系统定时任务"); |
| | | } |
| | | } |
| | | |
| | | } |
| | | //package com.iailab.module.system.job.demo; |
| | | // |
| | | //import com.iailab.framework.tenant.core.job.TenantJob; |
| | | //import com.xxl.job.core.handler.annotation.XxlJob; |
| | | //import org.slf4j.Logger; |
| | | //import org.slf4j.LoggerFactory; |
| | | //import org.springframework.stereotype.Component; |
| | | // |
| | | //import java.util.Date; |
| | | //import java.util.concurrent.atomic.AtomicInteger; |
| | | // |
| | | //@Component |
| | | //public class DemoJob { |
| | | // |
| | | // private Logger logger = LoggerFactory.getLogger(getClass()); |
| | | // |
| | | // private final AtomicInteger counts = new AtomicInteger(); |
| | | // |
| | | // private static final Object lock = new Object(); |
| | | // |
| | | // |
| | | // @XxlJob("demoJob") |
| | | // @TenantJob |
| | | // public void execute() { |
| | | // synchronized (lock) { |
| | | // logger.info("[execute][定时第 ({}) 次执行]", counts.incrementAndGet()); |
| | | // System.out.println(new Date() + ": 我是系统定时任务"); |
| | | // } |
| | | // } |
| | | // |
| | | //} |
| | |
| | | if(type == 1){ |
| | | menuDO.setCreator(loginUserNickname); |
| | | menuDO.setCreateTime(app.getCreateTime()); |
| | | menuDO.setIcon("fa-solid:border-none"); //默认icon |
| | | menuMapper.insert(menuDO); |
| | | // //内置租户角色分配菜单 |
| | | // assignRoleMenu(menuDO.getId(), app.getTenantId()); |
| | |
| | | List<MenuDO> filterDisableMenus(List<MenuDO> list); |
| | | |
| | | /** |
| | | * 过滤掉业务菜单或系统菜单及其子菜单 |
| | | * |
| | | * @param list 菜单列表 |
| | | * @return 过滤后的菜单列表 |
| | | */ |
| | | List<MenuDO> filterMenus(List<MenuDO> list, String type); |
| | | |
| | | /** |
| | | * 筛选菜单列表 |
| | | * |
| | | * @param reqVO 筛选条件请求 VO |
| | |
| | | import com.iailab.module.system.controller.admin.permission.vo.menu.MenuSaveVO; |
| | | import com.iailab.module.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppDO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppMenuDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.MenuDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.RoleDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.RoleMenuDO; |
| | | import com.iailab.module.system.dal.dataobject.tenant.TenantDO; |
| | | import com.iailab.module.system.dal.dataobject.tenant.TenantPackageDO; |
| | | import com.iailab.module.system.dal.mysql.app.AppMapper; |
| | | import com.iailab.module.system.dal.mysql.app.AppMenuMapper; |
| | | import com.iailab.module.system.dal.mysql.permission.MenuMapper; |
| | | import com.iailab.module.system.dal.mysql.permission.RoleMenuMapper; |
| | | import com.iailab.module.system.dal.redis.RedisKeyConstants; |
| | |
| | | import com.iailab.module.system.service.tenant.TenantPackageService; |
| | | import com.iailab.module.system.service.tenant.TenantService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.cache.annotation.CacheEvict; |
| | | import org.springframework.cache.annotation.Cacheable; |
| | | import org.springframework.context.annotation.Lazy; |
| | |
| | | |
| | | @Resource |
| | | private RoleMenuMapper roleMenuMapper; |
| | | @Autowired |
| | | private AppMapper appMapper; |
| | | @Autowired |
| | | private AppMenuMapper appMenuMapper; |
| | | |
| | | @Override |
| | | @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#createReqVO.permission", |
| | |
| | | //菜单归属租户和应用 |
| | | Long tenantId = getTenantId(); |
| | | AppDO appDO = appService.getAppByTenantId(tenantId); |
| | | updateObj.setTenantId(tenantId); |
| | | updateObj.setAppId(appDO.getId()); |
| | | if(appDO.getTenantId() != 1) { |
| | | updateObj.setTenantId(tenantId); |
| | | updateObj.setAppId(appDO.getId()); |
| | | } |
| | | menuMapper.updateById(updateObj); |
| | | } |
| | | |
| | |
| | | return enabledMenus; |
| | | } |
| | | |
| | | @Override |
| | | public List<MenuDO> filterMenus(List<MenuDO> menuList, String type) { |
| | | if (CollUtil.isEmpty(menuList)){ |
| | | return Collections.emptyList(); |
| | | } |
| | | Map<Long, MenuDO> menuMap = convertMap(menuList, MenuDO::getId); |
| | | LambdaQueryWrapper<AppDO> queryWrapper = new LambdaQueryWrapper<>(); |
| | | |
| | | //查询所有的系统应用菜单 |
| | | if("system".equals(type)) { |
| | | queryWrapper.eq(AppDO::getType, 0); |
| | | } else if("app".equals(type)) { |
| | | queryWrapper.eq(AppDO::getType, 1); |
| | | } |
| | | List<AppDO> appDOS = appMapper.selectList(queryWrapper); |
| | | List<Long> appIds = appDOS.stream().map(AppDO::getId).collect(Collectors.toList()); |
| | | List<MenuDO> menuDOS = menuMapper.selectList(new LambdaQueryWrapper<MenuDO>().in(MenuDO::getAppId, appIds)); |
| | | List<Long> systemMenuIds = menuDOS.stream().map(MenuDO::getId).collect(Collectors.toList()); |
| | | |
| | | // 遍历 menu 菜单,查找不是禁用的菜单,添加到 系统菜单(应用菜单) 结果 |
| | | List<MenuDO> systemMenus = new ArrayList<>(); |
| | | Set<Long> appMenuCache = new HashSet<>(); // 存下递归搜索过被禁用的菜单,防止重复的搜索 |
| | | for (MenuDO menu : menuList) { |
| | | if (isAppMenu(menu, menuMap, appMenuCache, systemMenuIds)) { |
| | | continue; |
| | | } |
| | | systemMenus.add(menu); |
| | | } |
| | | return systemMenus; |
| | | } |
| | | |
| | | private boolean isMenuDisabled(MenuDO node, Map<Long, MenuDO> menuMap, Set<Long> disabledMenuCache) { |
| | | // 如果已经判定是禁用的节点,直接结束 |
| | | if (disabledMenuCache.contains(node.getId())) { |
| | |
| | | return false; |
| | | } |
| | | |
| | | private boolean isAppMenu(MenuDO node, Map<Long, MenuDO> menuMap, Set<Long> menuCache, List<Long> systemMenuIds) { |
| | | // 如果已经判定是禁用的节点,直接结束 |
| | | if (menuCache.contains(node.getId())) { |
| | | return true; |
| | | } |
| | | |
| | | // 2. 遍历到 parentId 为根节点,则无需判断 |
| | | Long parentId = node.getParentId(); |
| | | if (ObjUtil.equal(parentId, ID_ROOT)) { |
| | | if (!systemMenuIds.contains(node.getId())) { |
| | | menuCache.add(node.getId()); |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // 3. 继续遍历 parent 节点 |
| | | MenuDO parent = menuMap.get(parentId); |
| | | if (parent == null || isAppMenu(parent, menuMap, menuCache, systemMenuIds)) { |
| | | menuCache.add(node.getId()); |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | @Override |
| | | public List<MenuDO> getMenuList(MenuListReqVO reqVO) { |
| | | return menuMapper.selectList(reqVO); |
| | |
| | | |
| | | @Override |
| | | public List<MenuDO> getAppMenuList(Long tenantId, MenuListReqVO reqVO) { |
| | | List<MenuDO> menuDOS = menuMapper.selectAppMenuList(tenantId, reqVO); |
| | | List<MenuDO> menuDOS = menuMapper.selectAppMenuList(reqVO); |
| | | menuDOS = filterMenus(menuDOS, "app"); |
| | | Set<Long> menuDOIds = menuDOS.stream().map(MenuDO::getId).collect(Collectors.toSet()); |
| | | TenantDO tenant = tenantService.getTenant(tenantId); |
| | | TenantPackageDO tenantPackage = tenantPackageService.getTenantPackage(tenant.getPackageId()); |
| | | Set<Long> tenantMenuIds = tenantPackage.getMenuIds(); |
| | | menuDOS = menuDOS.stream().filter(menuDO -> tenantMenuIds.contains(menuDO.getId())).collect(Collectors.toList()); |
| | | // 获得角色列表 |
| | | Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId()); |
| | | List<RoleDO> roles = roleService.getRoleList(roleIds); |
| | |
| | | <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version> |
| | | <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version> |
| | | <!-- 统一依赖管理 --> |
| | | <spring.framework.version>5.3.39</spring.framework.version> |
| | | <spring.security.version>5.8.14</spring.security.version> |
| | | <spring.boot.version>2.7.18</spring.boot.version> |
| | | <spring.cloud.version>2021.0.9</spring.cloud.version> |
| | | <spring.cloud.alibaba.version>2021.0.6.1</spring.cloud.alibaba.version> |
| | |
| | | <ip2region.version>2.7.0</ip2region.version> |
| | | <bizlog-sdk.version>3.0.6</bizlog-sdk.version> |
| | | <reflections.version>0.10.2</reflections.version> |
| | | <netty.version>4.1.113.Final</netty.version> |
| | | <!-- 三方云服务相关 --> |
| | | <okio.version>3.5.0</okio.version> |
| | | <okhttp3.version>4.11.0</okhttp3.version> |
| | |
| | | <aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version> |
| | | <tencentcloud-sdk-java.version>3.1.880</tencentcloud-sdk-java.version> |
| | | <justauth.version>1.0.8</justauth.version> |
| | | <jimureport.version>1.6.6</jimureport.version> |
| | | <jimureport.version>1.9.0</jimureport.version> |
| | | <xercesImpl.version>2.12.2</xercesImpl.version> |
| | | <weixin-java.version>4.6.0</weixin-java.version> |
| | | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
| | |
| | | <nacos.metadata.version>1.0.0</nacos.metadata.version> |
| | | <log.path>D:\DLUT\iailab-plat</log.path> |
| | | <logstash.address>127.0.0.1:4560</logstash.address> |
| | | <deploy.server>127.0.0.1</deploy.server> |
| | | <deploy.server>192.168.56.1</deploy.server> |
| | | </properties> |
| | | <activation> |
| | | <!-- 默认环境 --> |
| | |
| | | <profile> |
| | | <id>prod</id> |
| | | <properties> |
| | | <!-- 环境标识,需要与配置文件的名称相对应 --> |
| | | <profiles.active>prod</profiles.active> |
| | | <nacos.server>127.0.0.1:8848</nacos.server> |
| | | <nacos.discovery.group>DEFAULT_GROUP</nacos.discovery.group> |
| | | <nacos.config.group>DEFAULT_GROUP</nacos.config.group> |
| | | <nacos.namespace>a7112341-c9e2-4177-bc5b-0d2e8cf0b3bb</nacos.namespace> |
| | | <nacos.username>nacos</nacos.username> |
| | | <nacos.password>nacos</nacos.password> |
| | | <nacos.metadata.version>1.0.0</nacos.metadata.version> |
| | | <log.path>D:\iailab\logs</log.path> |
| | | <logstash.address>127.0.0.1:4560</logstash.address> |
| | | <deploy.server>10.88.4.131</deploy.server> |
| | | </properties> |
| | | </profile> |
| | | </profiles> |
| | |
| | | <dependencyManagement> |
| | | <dependencies> |
| | | <!-- 统一依赖管理 --> |
| | | <dependency> |
| | | <groupId>io.netty</groupId> |
| | | <artifactId>netty-bom</artifactId> |
| | | <version>${netty.version}</version> |
| | | <type>pom</type> |
| | | <scope>import</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework</groupId> |
| | | <artifactId>spring-framework-bom</artifactId> <!-- JDK8 版本独有:保证 Spring Framework 尽量高 --> |
| | | <version>${spring.framework.version}</version> |
| | | <type>pom</type> |
| | | <scope>import</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.security</groupId> |
| | | <artifactId>spring-security-bom</artifactId> <!-- JDK8 版本独有:保证 Spring Security 尽量高 --> |
| | | <version>${spring.security.version}</version> |
| | | <type>pom</type> |
| | | <scope>import</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-dependencies</artifactId> |
| | |
| | | </exclusion> |
| | | </exclusions> |
| | | </dependency> |
| | | <!-- 积木仪表盘--> |
| | | <dependency> |
| | | <groupId>org.jeecgframework.jimureport</groupId> |
| | | <artifactId>jimureport-dashboard-spring-boot-starter</artifactId> |
| | | <version>${jimureport.version}</version> |
| | | <exclusions> |
| | | <exclusion> |
| | | <artifactId>autopoi-web</artifactId> |
| | | <groupId>org.jeecgframework</groupId> |
| | | </exclusion> |
| | | <exclusion> |
| | | <groupId>org.jeecgframework.jimureport</groupId> |
| | | <artifactId>jimureport-spring-boot-starter</artifactId> |
| | | </exclusion> |
| | | </exclusions> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>xerces</groupId> |
| | | <artifactId>xercesImpl</artifactId> |