diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SwaggerController.java b/ruoyi-common/src/main/java/com/ruoyi/common/SwaggerController.java similarity index 85% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SwaggerController.java rename to ruoyi-common/src/main/java/com/ruoyi/common/SwaggerController.java index f66ca24ec..b79c15f4b 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SwaggerController.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/SwaggerController.java @@ -8,17 +8,15 @@ import com.ruoyi.common.core.controller.BaseController; /** * swagger 接口 - * + * * @author ruoyi */ @Controller @RequestMapping("/tool/swagger") -public class SwaggerController extends BaseController -{ +public class SwaggerController extends BaseController { @PreAuthorize("@ss.hasPermi('tool:swagger:view')") @GetMapping() - public String index() - { + public String index() { return redirect("/swagger-ui.html"); } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScopeAspect.java similarity index 97% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java rename to ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScopeAspect.java index 07abb1b04..cc01b9422 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScopeAspect.java @@ -1,145 +1,145 @@ -package com.ruoyi.framework.aspectj; - -import java.lang.reflect.Method; - -import org.aspectj.lang.JoinPoint; -import org.aspectj.lang.Signature; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; -import org.aspectj.lang.annotation.Pointcut; -import org.aspectj.lang.reflect.MethodSignature; -import org.springframework.stereotype.Component; -import com.ruoyi.common.annotation.DataScope; -import com.ruoyi.common.core.domain.BaseEntity; -import com.ruoyi.common.core.domain.entity.SysRole; -import com.ruoyi.common.core.domain.entity.SysUser; -import com.ruoyi.common.core.domain.model.LoginUser; -import com.ruoyi.common.utils.ServletUtils; -import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.common.utils.spring.SpringUtils; -import com.ruoyi.framework.web.service.TokenService; - -/** - * 数据过滤处理 - * - * @author ruoyi - */ -@Aspect -@Component -public class DataScopeAspect { - /** - * 全部数据权限 - */ - public static final String DATA_SCOPE_ALL = "1"; - - /** - * 自定数据权限 - */ - public static final String DATA_SCOPE_CUSTOM = "2"; - - /** - * 部门数据权限 - */ - public static final String DATA_SCOPE_DEPT = "3"; - - /** - * 部门及以下数据权限 - */ - public static final String DATA_SCOPE_DEPT_AND_CHILD = "4"; - - /** - * 仅本人数据权限 - */ - public static final String DATA_SCOPE_SELF = "5"; - - /** - * 数据权限过滤关键字 - */ - public static final String DATA_SCOPE = "dataScope"; - - // 配置织入点 - @Pointcut("@annotation(com.ruoyi.common.annotation.DataScope)") - public void dataScopePointCut() { - } - - @Before("dataScopePointCut()") - public void doBefore(JoinPoint point) throws Throwable { - handleDataScope(point); - } - - protected void handleDataScope(final JoinPoint joinPoint) { - // 获得注解 - DataScope controllerDataScope = getAnnotationLog(joinPoint); - if (controllerDataScope == null) { - return; - } - // 获取当前的用户 - LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest()); - if (StringUtils.isNotNull(loginUser)) { - SysUser currentUser = loginUser.getUser(); - // 如果是超级管理员,则不过滤数据 - if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) { - dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), - controllerDataScope.userAlias()); - } - } - } - - /** - * 数据范围过滤 - * - * @param joinPoint 切点 - * @param user 用户 - * @param userAlias 别名 - */ - public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias) { - StringBuilder sqlString = new StringBuilder(); - - for (SysRole role : user.getRoles()) { - String dataScope = role.getDataScope(); - if (DATA_SCOPE_ALL.equals(dataScope)) { - sqlString = new StringBuilder(); - break; - } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) { - sqlString.append(StringUtils.format( - " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, - role.getRoleId())); - } else if (DATA_SCOPE_DEPT.equals(dataScope)) { - sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId())); - } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) { - sqlString.append(StringUtils.format( - " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", - deptAlias, user.getDeptId(), user.getDeptId())); - } else if (DATA_SCOPE_SELF.equals(dataScope)) { - if (StringUtils.isNotBlank(userAlias)) { - sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId())); - } else { - // 数据权限为仅本人且没有userAlias别名不查询任何数据 - sqlString.append(" OR 1=0 "); - } - } - } - - if (StringUtils.isNotBlank(sqlString.toString())) { - Object params = joinPoint.getArgs()[0]; - if (StringUtils.isNotNull(params) && params instanceof BaseEntity) { - BaseEntity baseEntity = (BaseEntity) params; - baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")"); - } - } - } - - /** - * 是否存在注解,如果存在就获取 - */ - private DataScope getAnnotationLog(JoinPoint joinPoint) { - Signature signature = joinPoint.getSignature(); - MethodSignature methodSignature = (MethodSignature) signature; - Method method = methodSignature.getMethod(); - - if (method != null) { - return method.getAnnotation(DataScope.class); - } - return null; - } -} +package com.ruoyi.framework.aspectj; + +import java.lang.reflect.Method; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; +import com.ruoyi.common.annotation.DataScope; +import com.ruoyi.common.core.domain.BaseEntity; +import com.ruoyi.common.core.domain.entity.SysRole; +import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.core.domain.model.LoginUser; +import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.framework.web.service.TokenService; + +/** + * 数据过滤处理 + * + * @author ruoyi + */ +@Aspect +@Component +public class DataScopeAspect { + /** + * 全部数据权限 + */ + public static final String DATA_SCOPE_ALL = "1"; + + /** + * 自定数据权限 + */ + public static final String DATA_SCOPE_CUSTOM = "2"; + + /** + * 部门数据权限 + */ + public static final String DATA_SCOPE_DEPT = "3"; + + /** + * 部门及以下数据权限 + */ + public static final String DATA_SCOPE_DEPT_AND_CHILD = "4"; + + /** + * 仅本人数据权限 + */ + public static final String DATA_SCOPE_SELF = "5"; + + /** + * 数据权限过滤关键字 + */ + public static final String DATA_SCOPE = "dataScope"; + + // 配置织入点 + @Pointcut("@annotation(com.ruoyi.common.annotation.DataScope)") + public void dataScopePointCut() { + } + + @Before("dataScopePointCut()") + public void doBefore(JoinPoint point) throws Throwable { + handleDataScope(point); + } + + protected void handleDataScope(final JoinPoint joinPoint) { + // 获得注解 + DataScope controllerDataScope = getAnnotationLog(joinPoint); + if (controllerDataScope == null) { + return; + } + // 获取当前的用户 + LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest()); + if (StringUtils.isNotNull(loginUser)) { + SysUser currentUser = loginUser.getUser(); + // 如果是超级管理员,则不过滤数据 + if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) { + dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), + controllerDataScope.userAlias()); + } + } + } + + /** + * 数据范围过滤 + * + * @param joinPoint 切点 + * @param user 用户 + * @param userAlias 别名 + */ + public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias) { + StringBuilder sqlString = new StringBuilder(); + + for (SysRole role : user.getRoles()) { + String dataScope = role.getDataScope(); + if (DATA_SCOPE_ALL.equals(dataScope)) { + sqlString = new StringBuilder(); + break; + } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) { + sqlString.append(StringUtils.format( + " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, + role.getRoleId())); + } else if (DATA_SCOPE_DEPT.equals(dataScope)) { + sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId())); + } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) { + sqlString.append(StringUtils.format( + " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", + deptAlias, user.getDeptId(), user.getDeptId())); + } else if (DATA_SCOPE_SELF.equals(dataScope)) { + if (StringUtils.isNotBlank(userAlias)) { + sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId())); + } else { + // 数据权限为仅本人且没有userAlias别名不查询任何数据 + sqlString.append(" OR 1=0 "); + } + } + } + + if (StringUtils.isNotBlank(sqlString.toString())) { + Object params = joinPoint.getArgs()[0]; + if (StringUtils.isNotNull(params) && params instanceof BaseEntity) { + BaseEntity baseEntity = (BaseEntity) params; + baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")"); + } + } + } + + /** + * 是否存在注解,如果存在就获取 + */ + private DataScope getAnnotationLog(JoinPoint joinPoint) { + Signature signature = joinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + Method method = methodSignature.getMethod(); + + if (method != null) { + return method.getAnnotation(DataScope.class); + } + return null; + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSourceAspect.java similarity index 96% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java rename to ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSourceAspect.java index d3cdc4806..020493d2d 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSourceAspect.java @@ -1,64 +1,64 @@ -package com.ruoyi.framework.aspectj; - -import java.util.Objects; - -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Pointcut; -import org.aspectj.lang.reflect.MethodSignature; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; -import com.ruoyi.common.annotation.DataSource; -import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.framework.datasource.DynamicDataSourceContextHolder; - -/** - * 多数据源处理 - * - * @author ruoyi - */ -@Aspect -@Order(1) -@Component -public class DataSourceAspect { - protected Logger logger = LoggerFactory.getLogger(getClass()); - - @Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)" - + "|| @within(com.ruoyi.common.annotation.DataSource)") - public void dsPointCut() { - - } - - @Around("dsPointCut()") - public Object around(ProceedingJoinPoint point) throws Throwable { - DataSource dataSource = getDataSource(point); - - if (StringUtils.isNotNull(dataSource)) { - DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name()); - } - - try { - return point.proceed(); - } finally { - // 销毁数据源 在执行方法之后 - DynamicDataSourceContextHolder.clearDataSourceType(); - } - } - - /** - * 获取需要切换的数据源 - */ - public DataSource getDataSource(ProceedingJoinPoint point) { - MethodSignature signature = (MethodSignature) point.getSignature(); - DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class); - if (Objects.nonNull(dataSource)) { - return dataSource; - } - - return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class); - } -} +package com.ruoyi.framework.aspectj; + +import java.util.Objects; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import com.ruoyi.common.annotation.DataSource; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.framework.datasource.DynamicDataSourceContextHolder; + +/** + * 多数据源处理 + * + * @author ruoyi + */ +@Aspect +@Order(1) +@Component +public class DataSourceAspect { + protected Logger logger = LoggerFactory.getLogger(getClass()); + + @Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)" + + "|| @within(com.ruoyi.common.annotation.DataSource)") + public void dsPointCut() { + + } + + @Around("dsPointCut()") + public Object around(ProceedingJoinPoint point) throws Throwable { + DataSource dataSource = getDataSource(point); + + if (StringUtils.isNotNull(dataSource)) { + DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name()); + } + + try { + return point.proceed(); + } finally { + // 销毁数据源 在执行方法之后 + DynamicDataSourceContextHolder.clearDataSourceType(); + } + } + + /** + * 获取需要切换的数据源 + */ + public DataSource getDataSource(ProceedingJoinPoint point) { + MethodSignature signature = (MethodSignature) point.getSignature(); + DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class); + if (Objects.nonNull(dataSource)) { + return dataSource; + } + + return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSourceType.java similarity index 90% rename from ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java rename to ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSourceType.java index 4b5341d19..0d945be54 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSourceType.java @@ -1,19 +1,19 @@ -package com.ruoyi.common.enums; - -/** - * 数据源 - * - * @author ruoyi - */ -public enum DataSourceType -{ - /** - * 主库 - */ - MASTER, - - /** - * 从库 - */ - SLAVE -} +package com.ruoyi.common.enums; + +/** + * 数据源 + * + * @author ruoyi + */ +public enum DataSourceType +{ + /** + * 主库 + */ + MASTER, + + /** + * 从库 + */ + SLAVE +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DynamicDataSource.java similarity index 96% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java rename to ruoyi-common/src/main/java/com/ruoyi/common/annotation/DynamicDataSource.java index f12b1e543..f60b35cb6 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DynamicDataSource.java @@ -1,24 +1,24 @@ -package com.ruoyi.framework.datasource; - -import java.util.Map; -import javax.sql.DataSource; - -import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; - -/** - * 动态数据源 - * - * @author ruoyi - */ -public class DynamicDataSource extends AbstractRoutingDataSource { - public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) { - super.setDefaultTargetDataSource(defaultTargetDataSource); - super.setTargetDataSources(targetDataSources); - super.afterPropertiesSet(); - } - - @Override - protected Object determineCurrentLookupKey() { - return DynamicDataSourceContextHolder.getDataSourceType(); - } -} +package com.ruoyi.framework.datasource; + +import java.util.Map; +import javax.sql.DataSource; + +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + +/** + * 动态数据源 + * + * @author ruoyi + */ +public class DynamicDataSource extends AbstractRoutingDataSource { + public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) { + super.setDefaultTargetDataSource(defaultTargetDataSource); + super.setTargetDataSources(targetDataSources); + super.afterPropertiesSet(); + } + + @Override + protected Object determineCurrentLookupKey() { + return DynamicDataSourceContextHolder.getDataSourceType(); + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DynamicDataSourceContextHolder.java similarity index 96% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java rename to ruoyi-common/src/main/java/com/ruoyi/common/annotation/DynamicDataSourceContextHolder.java index 962d50cb2..37a5f8e58 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DynamicDataSourceContextHolder.java @@ -1,41 +1,41 @@ -package com.ruoyi.framework.datasource; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * 数据源切换处理 - * - * @author ruoyi - */ -public class DynamicDataSourceContextHolder { - public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class); - - /** - * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本, - * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 - */ - private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>(); - - /** - * 设置数据源的变量 - */ - public static void setDataSourceType(String dsType) { - log.info("切换到{}数据源", dsType); - CONTEXT_HOLDER.set(dsType); - } - - /** - * 获得数据源的变量 - */ - public static String getDataSourceType() { - return CONTEXT_HOLDER.get(); - } - - /** - * 清空数据源变量 - */ - public static void clearDataSourceType() { - CONTEXT_HOLDER.remove(); - } -} +package com.ruoyi.framework.datasource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 数据源切换处理 + * + * @author ruoyi + */ +public class DynamicDataSourceContextHolder { + public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class); + + /** + * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本, + * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 + */ + private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>(); + + /** + * 设置数据源的变量 + */ + public static void setDataSourceType(String dsType) { + log.info("切换到{}数据源", dsType); + CONTEXT_HOLDER.set(dsType); + } + + /** + * 获得数据源的变量 + */ + public static String getDataSourceType() { + return CONTEXT_HOLDER.get(); + } + + /** + * 清空数据源变量 + */ + public static void clearDataSourceType() { + CONTEXT_HOLDER.remove(); + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/DruidConfig.java similarity index 97% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java rename to ruoyi-common/src/main/java/com/ruoyi/common/config/DruidConfig.java index 512317ade..7e9f4b03f 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/DruidConfig.java @@ -1,116 +1,116 @@ -package com.ruoyi.framework.config; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.sql.DataSource; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import com.alibaba.druid.pool.DruidDataSource; -import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; -import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; -import com.alibaba.druid.util.Utils; -import com.ruoyi.common.enums.DataSourceType; -import com.ruoyi.common.utils.spring.SpringUtils; -import com.ruoyi.framework.config.properties.DruidProperties; -import com.ruoyi.framework.datasource.DynamicDataSource; - -/** - * druid 配置多数据源 - * - * @author ruoyi - */ -@Configuration -public class DruidConfig { - @Bean - @ConfigurationProperties("spring.datasource.druid.master") - public DataSource masterDataSource(DruidProperties druidProperties) { - DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); - return druidProperties.dataSource(dataSource); - } - - @Bean - @ConfigurationProperties("spring.datasource.druid.slave") - @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") - public DataSource slaveDataSource(DruidProperties druidProperties) { - DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); - return druidProperties.dataSource(dataSource); - } - - @Bean(name = "dynamicDataSource") - @Primary - public DynamicDataSource dataSource(DataSource masterDataSource) { - Map targetDataSources = new HashMap<>(); - targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource); - setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource"); - return new DynamicDataSource(masterDataSource, targetDataSources); - } - - /** - * 设置数据源 - * - * @param targetDataSources 备选数据源集合 - * @param sourceName 数据源名称 - * @param beanName bean名称 - */ - public void setDataSource(Map targetDataSources, String sourceName, String beanName) { - try { - DataSource dataSource = SpringUtils.getBean(beanName); - targetDataSources.put(sourceName, dataSource); - } catch (Exception e) { - } - } - - /** - * 去除监控页面底部的广告 - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - @Bean - @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true") - public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) { - // 获取web监控页面的参数 - DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); - // 提取common.js的配置路径 - String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; - String commonJsPattern = pattern.replaceAll("\\*", "js/common.js"); - final String filePath = "support/http/resources/js/common.js"; - // 创建filter进行过滤 - Filter filter = new Filter() { - @Override - public void init(javax.servlet.FilterConfig filterConfig) throws ServletException { - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - chain.doFilter(request, response); - // 重置缓冲区,响应头不会被重置 - response.resetBuffer(); - // 获取common.js - String text = Utils.readFromResource(filePath); - // 正则替换banner, 除去底部的广告信息 - text = text.replaceAll("
", ""); - text = text.replaceAll("powered.*?shrek.wang", ""); - response.getWriter().write(text); - } - - @Override - public void destroy() { - } - }; - FilterRegistrationBean registrationBean = new FilterRegistrationBean(); - registrationBean.setFilter(filter); - registrationBean.addUrlPatterns(commonJsPattern); - return registrationBean; - } -} +package com.ruoyi.framework.config; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.sql.DataSource; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; +import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; +import com.alibaba.druid.util.Utils; +import com.ruoyi.common.enums.DataSourceType; +import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.framework.config.properties.DruidProperties; +import com.ruoyi.framework.datasource.DynamicDataSource; + +/** + * druid 配置多数据源 + * + * @author ruoyi + */ +@Configuration +public class DruidConfig { + @Bean + @ConfigurationProperties("spring.datasource.druid.master") + public DataSource masterDataSource(DruidProperties druidProperties) { + DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); + return druidProperties.dataSource(dataSource); + } + + @Bean + @ConfigurationProperties("spring.datasource.druid.slave") + @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") + public DataSource slaveDataSource(DruidProperties druidProperties) { + DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); + return druidProperties.dataSource(dataSource); + } + + @Bean(name = "dynamicDataSource") + @Primary + public DynamicDataSource dataSource(DataSource masterDataSource) { + Map targetDataSources = new HashMap<>(); + targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource); + setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource"); + return new DynamicDataSource(masterDataSource, targetDataSources); + } + + /** + * 设置数据源 + * + * @param targetDataSources 备选数据源集合 + * @param sourceName 数据源名称 + * @param beanName bean名称 + */ + public void setDataSource(Map targetDataSources, String sourceName, String beanName) { + try { + DataSource dataSource = SpringUtils.getBean(beanName); + targetDataSources.put(sourceName, dataSource); + } catch (Exception e) { + } + } + + /** + * 去除监控页面底部的广告 + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + @Bean + @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true") + public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) { + // 获取web监控页面的参数 + DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); + // 提取common.js的配置路径 + String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; + String commonJsPattern = pattern.replaceAll("\\*", "js/common.js"); + final String filePath = "support/http/resources/js/common.js"; + // 创建filter进行过滤 + Filter filter = new Filter() { + @Override + public void init(javax.servlet.FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + chain.doFilter(request, response); + // 重置缓冲区,响应头不会被重置 + response.resetBuffer(); + // 获取common.js + String text = Utils.readFromResource(filePath); + // 正则替换banner, 除去底部的广告信息 + text = text.replaceAll("
", ""); + text = text.replaceAll("powered.*?shrek.wang", ""); + response.getWriter().write(text); + } + + @Override + public void destroy() { + } + }; + FilterRegistrationBean registrationBean = new FilterRegistrationBean(); + registrationBean.setFilter(filter); + registrationBean.addUrlPatterns(commonJsPattern); + return registrationBean; + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/FilterConfig.java similarity index 97% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java rename to ruoyi-common/src/main/java/com/ruoyi/common/config/FilterConfig.java index 70a2a4a27..4feef0d0b 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/FilterConfig.java @@ -1,58 +1,58 @@ -package com.ruoyi.framework.config; - -import java.util.HashMap; -import java.util.Map; -import javax.servlet.DispatcherType; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import com.ruoyi.common.filter.RepeatableFilter; -import com.ruoyi.common.filter.XssFilter; -import com.ruoyi.common.utils.StringUtils; - -/** - * Filter配置 - * - * @author ruoyi - */ -@Configuration -public class FilterConfig { - @Value("${xss.enabled}") - private String enabled; - - @Value("${xss.excludes}") - private String excludes; - - @Value("${xss.urlPatterns}") - private String urlPatterns; - - @SuppressWarnings({"rawtypes", "unchecked"}) - @Bean - public FilterRegistrationBean xssFilterRegistration() { - FilterRegistrationBean registration = new FilterRegistrationBean(); - registration.setDispatcherTypes(DispatcherType.REQUEST); - registration.setFilter(new XssFilter()); - registration.addUrlPatterns(StringUtils.split(urlPatterns, ",")); - registration.setName("xssFilter"); - registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); - Map initParameters = new HashMap(); - initParameters.put("excludes", excludes); - initParameters.put("enabled", enabled); - registration.setInitParameters(initParameters); - return registration; - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - @Bean - public FilterRegistrationBean someFilterRegistration() { - FilterRegistrationBean registration = new FilterRegistrationBean(); - registration.setFilter(new RepeatableFilter()); - registration.addUrlPatterns("/*"); - registration.setName("repeatableFilter"); - registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE); - return registration; - } - -} +package com.ruoyi.framework.config; + +import java.util.HashMap; +import java.util.Map; +import javax.servlet.DispatcherType; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import com.ruoyi.common.filter.RepeatableFilter; +import com.ruoyi.common.filter.XssFilter; +import com.ruoyi.common.utils.StringUtils; + +/** + * Filter配置 + * + * @author ruoyi + */ +@Configuration +public class FilterConfig { + @Value("${xss.enabled}") + private String enabled; + + @Value("${xss.excludes}") + private String excludes; + + @Value("${xss.urlPatterns}") + private String urlPatterns; + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Bean + public FilterRegistrationBean xssFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setDispatcherTypes(DispatcherType.REQUEST); + registration.setFilter(new XssFilter()); + registration.addUrlPatterns(StringUtils.split(urlPatterns, ",")); + registration.setName("xssFilter"); + registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); + Map initParameters = new HashMap(); + initParameters.put("excludes", excludes); + initParameters.put("enabled", enabled); + registration.setInitParameters(initParameters); + return registration; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Bean + public FilterRegistrationBean someFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(new RepeatableFilter()); + registration.addUrlPatterns("/*"); + registration.setName("repeatableFilter"); + registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE); + return registration; + } + +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/ResourcesConfig.java similarity index 97% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java rename to ruoyi-common/src/main/java/com/ruoyi/common/config/ResourcesConfig.java index edf35f527..b5d749c0a 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/ResourcesConfig.java @@ -1,44 +1,44 @@ -package com.ruoyi.framework.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import org.springframework.web.filter.CorsFilter; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import com.ruoyi.common.config.RuoYiConfig; -import com.ruoyi.common.constant.Constants; -import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; - -/** - * 通用配置 - * - * @author ruoyi - */ -@Configuration -public class ResourcesConfig implements WebMvcConfigurer { - @Autowired - private RepeatSubmitInterceptor repeatSubmitInterceptor; - - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { - /** 本地文件上传路径 */ - registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/"); - - /** swagger配置 */ - registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); - registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); - } - - /** - * 自定义拦截规则 - */ - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**"); - } - -} +package com.ruoyi.framework.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; + +/** + * 通用配置 + * + * @author ruoyi + */ +@Configuration +public class ResourcesConfig implements WebMvcConfigurer { + @Autowired + private RepeatSubmitInterceptor repeatSubmitInterceptor; + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + /** 本地文件上传路径 */ + registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/"); + + /** swagger配置 */ + registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); + } + + /** + * 自定义拦截规则 + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**"); + } + +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ServerConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/ServerConfig.java similarity index 96% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/ServerConfig.java rename to ruoyi-common/src/main/java/com/ruoyi/common/config/ServerConfig.java index 4692363d0..d50be60aa 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ServerConfig.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/ServerConfig.java @@ -1,30 +1,30 @@ -package com.ruoyi.framework.config; - -import javax.servlet.http.HttpServletRequest; - -import org.springframework.stereotype.Component; -import com.ruoyi.common.utils.ServletUtils; - -/** - * 服务相关配置 - * - * @author ruoyi - */ -@Component -public class ServerConfig { - /** - * 获取完整的请求路径,包括:域名,端口,上下文访问路径 - * - * @return 服务地址 - */ - public String getUrl() { - HttpServletRequest request = ServletUtils.getRequest(); - return getDomain(request); - } - - public static String getDomain(HttpServletRequest request) { - StringBuffer url = request.getRequestURL(); - String contextPath = request.getServletContext().getContextPath(); - return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString(); - } -} +package com.ruoyi.framework.config; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Component; +import com.ruoyi.common.utils.ServletUtils; + +/** + * 服务相关配置 + * + * @author ruoyi + */ +@Component +public class ServerConfig { + /** + * 获取完整的请求路径,包括:域名,端口,上下文访问路径 + * + * @return 服务地址 + */ + public String getUrl() { + HttpServletRequest request = ServletUtils.getRequest(); + return getDomain(request); + } + + public static String getDomain(HttpServletRequest request) { + StringBuffer url = request.getRequestURL(); + String contextPath = request.getServletContext().getContextPath(); + return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString(); + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/ThreadPoolConfig.java similarity index 97% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java rename to ruoyi-common/src/main/java/com/ruoyi/common/config/ThreadPoolConfig.java index b157d7877..dac6f6e8b 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/ThreadPoolConfig.java @@ -1,58 +1,58 @@ -package com.ruoyi.framework.config; - -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadPoolExecutor; - -import org.apache.commons.lang3.concurrent.BasicThreadFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -import com.ruoyi.common.utils.Threads; - -/** - * 线程池配置 - * - * @author ruoyi - **/ -@Configuration -public class ThreadPoolConfig { - // 核心线程池大小 - private int corePoolSize = 50; - - // 最大可创建的线程数 - private int maxPoolSize = 200; - - // 队列最大长度 - private int queueCapacity = 1000; - - // 线程池维护线程所允许的空闲时间 - private int keepAliveSeconds = 300; - - @Bean(name = "threadPoolTaskExecutor") - public ThreadPoolTaskExecutor threadPoolTaskExecutor() { - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - executor.setMaxPoolSize(maxPoolSize); - executor.setCorePoolSize(corePoolSize); - executor.setQueueCapacity(queueCapacity); - executor.setKeepAliveSeconds(keepAliveSeconds); - // 线程池对拒绝任务(无线程可用)的处理策略 - executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); - return executor; - } - - /** - * 执行周期性或定时任务 - */ - @Bean(name = "scheduledExecutorService") - protected ScheduledExecutorService scheduledExecutorService() { - return new ScheduledThreadPoolExecutor(corePoolSize, - new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) { - @Override - protected void afterExecute(Runnable r, Throwable t) { - super.afterExecute(r, t); - Threads.printException(r, t); - } - }; - } -} +package com.ruoyi.framework.config; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; + +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import com.ruoyi.common.utils.Threads; + +/** + * 线程池配置 + * + * @author ruoyi + **/ +@Configuration +public class ThreadPoolConfig { + // 核心线程池大小 + private int corePoolSize = 50; + + // 最大可创建的线程数 + private int maxPoolSize = 200; + + // 队列最大长度 + private int queueCapacity = 1000; + + // 线程池维护线程所允许的空闲时间 + private int keepAliveSeconds = 300; + + @Bean(name = "threadPoolTaskExecutor") + public ThreadPoolTaskExecutor threadPoolTaskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setMaxPoolSize(maxPoolSize); + executor.setCorePoolSize(corePoolSize); + executor.setQueueCapacity(queueCapacity); + executor.setKeepAliveSeconds(keepAliveSeconds); + // 线程池对拒绝任务(无线程可用)的处理策略 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + return executor; + } + + /** + * 执行周期性或定时任务 + */ + @Bean(name = "scheduledExecutorService") + protected ScheduledExecutorService scheduledExecutorService() { + return new ScheduledThreadPoolExecutor(corePoolSize, + new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) { + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + Threads.printException(r, t); + } + }; + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/properties/DruidProperties.java similarity index 97% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java rename to ruoyi-common/src/main/java/com/ruoyi/common/config/properties/DruidProperties.java index 2ca02648b..339839001 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/properties/DruidProperties.java @@ -1,75 +1,75 @@ -package com.ruoyi.framework.config.properties; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; -import com.alibaba.druid.pool.DruidDataSource; - -/** - * druid 配置属性 - * - * @author ruoyi - */ -@Configuration -public class DruidProperties { - @Value("${spring.datasource.druid.initialSize}") - private int initialSize; - - @Value("${spring.datasource.druid.minIdle}") - private int minIdle; - - @Value("${spring.datasource.druid.maxActive}") - private int maxActive; - - @Value("${spring.datasource.druid.maxWait}") - private int maxWait; - - @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}") - private int timeBetweenEvictionRunsMillis; - - @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}") - private int minEvictableIdleTimeMillis; - - @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}") - private int maxEvictableIdleTimeMillis; - - @Value("${spring.datasource.druid.validationQuery}") - private String validationQuery; - - @Value("${spring.datasource.druid.testWhileIdle}") - private boolean testWhileIdle; - - @Value("${spring.datasource.druid.testOnBorrow}") - private boolean testOnBorrow; - - @Value("${spring.datasource.druid.testOnReturn}") - private boolean testOnReturn; - - public DruidDataSource dataSource(DruidDataSource datasource) { - /** 配置初始化大小、最小、最大 */ - datasource.setInitialSize(initialSize); - datasource.setMaxActive(maxActive); - datasource.setMinIdle(minIdle); - - /** 配置获取连接等待超时的时间 */ - datasource.setMaxWait(maxWait); - - /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */ - datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); - - /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */ - datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); - datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis); - - /** - * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。 - */ - datasource.setValidationQuery(validationQuery); - /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */ - datasource.setTestWhileIdle(testWhileIdle); - /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ - datasource.setTestOnBorrow(testOnBorrow); - /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ - datasource.setTestOnReturn(testOnReturn); - return datasource; - } -} +package com.ruoyi.framework.config.properties; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import com.alibaba.druid.pool.DruidDataSource; + +/** + * druid 配置属性 + * + * @author ruoyi + */ +@Configuration +public class DruidProperties { + @Value("${spring.datasource.druid.initialSize}") + private int initialSize; + + @Value("${spring.datasource.druid.minIdle}") + private int minIdle; + + @Value("${spring.datasource.druid.maxActive}") + private int maxActive; + + @Value("${spring.datasource.druid.maxWait}") + private int maxWait; + + @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}") + private int timeBetweenEvictionRunsMillis; + + @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}") + private int minEvictableIdleTimeMillis; + + @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}") + private int maxEvictableIdleTimeMillis; + + @Value("${spring.datasource.druid.validationQuery}") + private String validationQuery; + + @Value("${spring.datasource.druid.testWhileIdle}") + private boolean testWhileIdle; + + @Value("${spring.datasource.druid.testOnBorrow}") + private boolean testOnBorrow; + + @Value("${spring.datasource.druid.testOnReturn}") + private boolean testOnReturn; + + public DruidDataSource dataSource(DruidDataSource datasource) { + /** 配置初始化大小、最小、最大 */ + datasource.setInitialSize(initialSize); + datasource.setMaxActive(maxActive); + datasource.setMinIdle(minIdle); + + /** 配置获取连接等待超时的时间 */ + datasource.setMaxWait(maxWait); + + /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */ + datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); + + /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */ + datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); + datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis); + + /** + * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。 + */ + datasource.setValidationQuery(validationQuery); + /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */ + datasource.setTestWhileIdle(testWhileIdle); + /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ + datasource.setTestOnBorrow(testOnBorrow); + /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ + datasource.setTestOnReturn(testOnReturn); + return datasource; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatSubmit.java similarity index 95% rename from ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java rename to ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatSubmit.java index 5f81b40bb..29c667f86 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatSubmit.java @@ -1,21 +1,21 @@ -package com.ruoyi.common.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * 自定义注解防止表单重复提交 - * - * @author ruoyi - */ -@Inherited -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface RepeatSubmit { - -} +package com.ruoyi.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义注解防止表单重复提交 + * + * @author ruoyi + */ +@Inherited +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RepeatSubmit { + +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatSubmitInterceptor.java similarity index 97% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java rename to ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatSubmitInterceptor.java index bb7644b2a..e07e6de65 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatSubmitInterceptor.java @@ -1,49 +1,49 @@ -package com.ruoyi.framework.interceptor; - -import java.lang.reflect.Method; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.stereotype.Component; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; -import com.alibaba.fastjson.JSONObject; -import com.ruoyi.common.annotation.RepeatSubmit; -import com.ruoyi.common.core.domain.AjaxResult; -import com.ruoyi.common.utils.ServletUtils; - -/** - * 防止重复提交拦截器 - * - * @author ruoyi - */ -@Component -public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter { - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - if (handler instanceof HandlerMethod) { - HandlerMethod handlerMethod = (HandlerMethod) handler; - Method method = handlerMethod.getMethod(); - RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); - if (annotation != null) { - if (this.isRepeatSubmit(request)) { - AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试"); - ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult)); - return false; - } - } - return true; - } else { - return super.preHandle(request, response, handler); - } - } - - /** - * 验证是否重复提交由子类实现具体的防重复提交的规则 - * - * @param request - * @return - * @throws Exception - */ - public abstract boolean isRepeatSubmit(HttpServletRequest request); -} +package com.ruoyi.framework.interceptor; + +import java.lang.reflect.Method; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.utils.ServletUtils; + +/** + * 防止重复提交拦截器 + * + * @author ruoyi + */ +@Component +public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter { + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if (handler instanceof HandlerMethod) { + HandlerMethod handlerMethod = (HandlerMethod) handler; + Method method = handlerMethod.getMethod(); + RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); + if (annotation != null) { + if (this.isRepeatSubmit(request)) { + AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试"); + ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult)); + return false; + } + } + return true; + } else { + return super.preHandle(request, response, handler); + } + } + + /** + * 验证是否重复提交由子类实现具体的防重复提交的规则 + * + * @param request + * @return + * @throws Exception + */ + public abstract boolean isRepeatSubmit(HttpServletRequest request); +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/SameUrlDataInterceptor.java similarity index 97% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java rename to ruoyi-common/src/main/java/com/ruoyi/common/filter/SameUrlDataInterceptor.java index 8b25ab0c5..3386b4115 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/SameUrlDataInterceptor.java @@ -1,114 +1,114 @@ -package com.ruoyi.framework.interceptor.impl; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import javax.servlet.http.HttpServletRequest; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import com.alibaba.fastjson.JSONObject; -import com.ruoyi.common.constant.Constants; -import com.ruoyi.common.core.redis.RedisCache; -import com.ruoyi.common.filter.RepeatedlyRequestWrapper; -import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.common.utils.http.HttpHelper; -import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; - -/** - * 判断请求url和数据是否和上一次相同, - * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。 - * - * @author ruoyi - */ -@Component -public class SameUrlDataInterceptor extends RepeatSubmitInterceptor { - public final String REPEAT_PARAMS = "repeatParams"; - - public final String REPEAT_TIME = "repeatTime"; - - // 令牌自定义标识 - @Value("${token.header}") - private String header; - - @Autowired - private RedisCache redisCache; - - /** - * 间隔时间,单位:秒 默认10秒 - *

- * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据 - */ - private int intervalTime = 10; - - public void setIntervalTime(int intervalTime) { - this.intervalTime = intervalTime; - } - - @SuppressWarnings("unchecked") - @Override - public boolean isRepeatSubmit(HttpServletRequest request) { - String nowParams = ""; - if (request instanceof RepeatedlyRequestWrapper) { - RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request; - nowParams = HttpHelper.getBodyString(repeatedlyRequest); - } - - // body参数为空,获取Parameter的数据 - if (StringUtils.isEmpty(nowParams)) { - nowParams = JSONObject.toJSONString(request.getParameterMap()); - } - Map nowDataMap = new HashMap(); - nowDataMap.put(REPEAT_PARAMS, nowParams); - nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); - - // 请求地址(作为存放cache的key值) - String url = request.getRequestURI(); - - // 唯一值(没有消息头则使用请求地址) - String submitKey = request.getHeader(header); - if (StringUtils.isEmpty(submitKey)) { - submitKey = url; - } - - // 唯一标识(指定key + 消息头) - String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey; - - Object sessionObj = redisCache.getCacheObject(cache_repeat_key); - if (sessionObj != null) { - Map sessionMap = (Map) sessionObj; - if (sessionMap.containsKey(url)) { - Map preDataMap = (Map) sessionMap.get(url); - if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap)) { - return true; - } - } - } - Map cacheMap = new HashMap(); - cacheMap.put(url, nowDataMap); - redisCache.setCacheObject(cache_repeat_key, cacheMap, intervalTime, TimeUnit.SECONDS); - return false; - } - - /** - * 判断参数是否相同 - */ - private boolean compareParams(Map nowMap, Map preMap) { - String nowParams = (String) nowMap.get(REPEAT_PARAMS); - String preParams = (String) preMap.get(REPEAT_PARAMS); - return nowParams.equals(preParams); - } - - /** - * 判断两次间隔时间 - */ - private boolean compareTime(Map nowMap, Map preMap) { - long time1 = (Long) nowMap.get(REPEAT_TIME); - long time2 = (Long) preMap.get(REPEAT_TIME); - if ((time1 - time2) < (this.intervalTime * 1000)) { - return true; - } - return false; - } -} +package com.ruoyi.framework.interceptor.impl; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.core.redis.RedisCache; +import com.ruoyi.common.filter.RepeatedlyRequestWrapper; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.http.HttpHelper; +import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; + +/** + * 判断请求url和数据是否和上一次相同, + * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。 + * + * @author ruoyi + */ +@Component +public class SameUrlDataInterceptor extends RepeatSubmitInterceptor { + public final String REPEAT_PARAMS = "repeatParams"; + + public final String REPEAT_TIME = "repeatTime"; + + // 令牌自定义标识 + @Value("${token.header}") + private String header; + + @Autowired + private RedisCache redisCache; + + /** + * 间隔时间,单位:秒 默认10秒 + *

+ * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据 + */ + private int intervalTime = 10; + + public void setIntervalTime(int intervalTime) { + this.intervalTime = intervalTime; + } + + @SuppressWarnings("unchecked") + @Override + public boolean isRepeatSubmit(HttpServletRequest request) { + String nowParams = ""; + if (request instanceof RepeatedlyRequestWrapper) { + RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request; + nowParams = HttpHelper.getBodyString(repeatedlyRequest); + } + + // body参数为空,获取Parameter的数据 + if (StringUtils.isEmpty(nowParams)) { + nowParams = JSONObject.toJSONString(request.getParameterMap()); + } + Map nowDataMap = new HashMap(); + nowDataMap.put(REPEAT_PARAMS, nowParams); + nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); + + // 请求地址(作为存放cache的key值) + String url = request.getRequestURI(); + + // 唯一值(没有消息头则使用请求地址) + String submitKey = request.getHeader(header); + if (StringUtils.isEmpty(submitKey)) { + submitKey = url; + } + + // 唯一标识(指定key + 消息头) + String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey; + + Object sessionObj = redisCache.getCacheObject(cache_repeat_key); + if (sessionObj != null) { + Map sessionMap = (Map) sessionObj; + if (sessionMap.containsKey(url)) { + Map preDataMap = (Map) sessionMap.get(url); + if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap)) { + return true; + } + } + } + Map cacheMap = new HashMap(); + cacheMap.put(url, nowDataMap); + redisCache.setCacheObject(cache_repeat_key, cacheMap, intervalTime, TimeUnit.SECONDS); + return false; + } + + /** + * 判断参数是否相同 + */ + private boolean compareParams(Map nowMap, Map preMap) { + String nowParams = (String) nowMap.get(REPEAT_PARAMS); + String preParams = (String) preMap.get(REPEAT_PARAMS); + return nowParams.equals(preParams); + } + + /** + * 判断两次间隔时间 + */ + private boolean compareTime(Map nowMap, Map preMap) { + long time1 = (Long) nowMap.get(REPEAT_TIME); + long time2 = (Long) preMap.get(REPEAT_TIME); + if ((time1 - time2) < (this.intervalTime * 1000)) { + return true; + } + return false; + } +} diff --git a/ruoyi-admin/src/main/resources/application-druid.yml b/ruoyi-common/src/main/resources/application-druid.yml similarity index 95% rename from ruoyi-admin/src/main/resources/application-druid.yml rename to ruoyi-common/src/main/resources/application-druid.yml index cdfb3390b..13e1a5c36 100644 --- a/ruoyi-admin/src/main/resources/application-druid.yml +++ b/ruoyi-common/src/main/resources/application-druid.yml @@ -1,57 +1,57 @@ -# 数据源配置 -spring: - datasource: - type: com.alibaba.druid.pool.DruidDataSource - driverClassName: com.mysql.cj.jdbc.Driver - druid: - # 主库数据源 - master: - url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 - username: root - password: password - # 从库数据源 - slave: - # 从数据源开关/默认关闭 - enabled: false - url: - username: - password: - # 初始连接数 - initialSize: 5 - # 最小连接池数量 - minIdle: 10 - # 最大连接池数量 - maxActive: 20 - # 配置获取连接等待超时的时间 - maxWait: 60000 - # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 - timeBetweenEvictionRunsMillis: 60000 - # 配置一个连接在池中最小生存的时间,单位是毫秒 - minEvictableIdleTimeMillis: 300000 - # 配置一个连接在池中最大生存的时间,单位是毫秒 - maxEvictableIdleTimeMillis: 900000 - # 配置检测连接是否有效 - validationQuery: SELECT 1 FROM DUAL - testWhileIdle: true - testOnBorrow: false - testOnReturn: false - webStatFilter: - enabled: true - statViewServlet: - enabled: true - # 设置白名单,不填则允许所有访问 - allow: - url-pattern: /druid/* - # 控制台管理用户名和密码 - login-username: - login-password: - filter: - stat: - enabled: true - # 慢SQL记录 - log-slow-sql: true - slow-sql-millis: 1000 - merge-sql: true - wall: - config: +# 数据源配置 +spring: + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driverClassName: com.mysql.cj.jdbc.Driver + druid: + # 主库数据源 + master: + url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + username: root + password: password + # 从库数据源 + slave: + # 从数据源开关/默认关闭 + enabled: false + url: + username: + password: + # 初始连接数 + initialSize: 5 + # 最小连接池数量 + minIdle: 10 + # 最大连接池数量 + maxActive: 20 + # 配置获取连接等待超时的时间 + maxWait: 60000 + # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + timeBetweenEvictionRunsMillis: 60000 + # 配置一个连接在池中最小生存的时间,单位是毫秒 + minEvictableIdleTimeMillis: 300000 + # 配置一个连接在池中最大生存的时间,单位是毫秒 + maxEvictableIdleTimeMillis: 900000 + # 配置检测连接是否有效 + validationQuery: SELECT 1 FROM DUAL + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + webStatFilter: + enabled: true + statViewServlet: + enabled: true + # 设置白名单,不填则允许所有访问 + allow: + url-pattern: /druid/* + # 控制台管理用户名和密码 + login-username: + login-password: + filter: + stat: + enabled: true + # 慢SQL记录 + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: multi-statement-allow: true \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-common/src/main/resources/application.yml similarity index 95% rename from ruoyi-admin/src/main/resources/application.yml rename to ruoyi-common/src/main/resources/application.yml index e2c99b186..8adc0a845 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-common/src/main/resources/application.yml @@ -1,44 +1,44 @@ -# 项目相关配置 -ruoyi: - # 名称 - name: RuoYi - # 版本 - version: 3.3.0 - # 版权年份 - copyrightYear: 2020 - # 实例演示开关 - demoEnabled: true - # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) - profile: D:/ruoyi/uploadPath - # 获取ip地址开关 - addressEnabled: false - -# 开发环境配置 -server: - # 服务器的HTTP端口,默认为8080 - port: 8080 - servlet: - # 应用的访问路径 - context-path: / - tomcat: - # tomcat的URI编码 - uri-encoding: UTF-8 - # tomcat最大线程数,默认为200 - max-threads: 800 - # Tomcat启动初始化的线程数,默认值25 - min-spare-threads: 30 - -# 日志配置 -logging: - level: - com.ruoyi: debug - org.springframework: warn - -# 防止XSS攻击 -xss: - # 过滤开关 - enabled: true - # 排除链接(多个用逗号分隔) - excludes: /system/notice/* - # 匹配链接 - urlPatterns: /system/*,/monitor/*,/tool/* +# 项目相关配置 +ruoyi: + # 名称 + name: RuoYi + # 版本 + version: 3.3.0 + # 版权年份 + copyrightYear: 2020 + # 实例演示开关 + demoEnabled: true + # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) + profile: D:/ruoyi/uploadPath + # 获取ip地址开关 + addressEnabled: false + +# 开发环境配置 +server: + # 服务器的HTTP端口,默认为8080 + port: 8080 + servlet: + # 应用的访问路径 + context-path: / + tomcat: + # tomcat的URI编码 + uri-encoding: UTF-8 + # tomcat最大线程数,默认为200 + max-threads: 800 + # Tomcat启动初始化的线程数,默认值25 + min-spare-threads: 30 + +# 日志配置 +logging: + level: + com.ruoyi: debug + org.springframework: warn + +# 防止XSS攻击 +xss: + # 过滤开关 + enabled: true + # 排除链接(多个用逗号分隔) + excludes: /system/notice/* + # 匹配链接 + urlPatterns: /system/*,/monitor/*,/tool/* diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/ruoyi-common/src/main/resources/i18n/messages.properties similarity index 98% rename from ruoyi-admin/src/main/resources/i18n/messages.properties rename to ruoyi-common/src/main/resources/i18n/messages.properties index 4baeb241a..d63aa1f8a 100644 --- a/ruoyi-admin/src/main/resources/i18n/messages.properties +++ b/ruoyi-common/src/main/resources/i18n/messages.properties @@ -1,36 +1,36 @@ -#错误消息 -not.null=* 必须填写 -user.jcaptcha.error=验证码错误 -user.jcaptcha.expire=验证码已失效 -user.not.exists=用户不存在/密码错误 -user.password.not.match=用户不存在/密码错误 -user.password.retry.limit.count=密码输入错误{0}次 -user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟 -user.password.delete=对不起,您的账号已被删除 -user.blocked=用户已封禁,请联系管理员 -role.blocked=角色已封禁,请联系管理员 -user.logout.success=退出成功 - -length.not.valid=长度必须在{min}到{max}个字符之间 - -user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 -user.password.not.valid=* 5-50个字符 - -user.email.not.valid=邮箱格式错误 -user.mobile.phone.number.not.valid=手机号格式错误 -user.login.success=登录成功 -user.notfound=请重新登录 -user.forcelogout=管理员强制退出,请重新登录 -user.unknown.error=未知错误,请重新登录 - -##文件上传消息 -upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! -upload.filename.exceed.length=上传的文件名最长{0}个字符 - -##权限 -no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] -no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] -no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] -no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] -no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] -no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=用户不存在/密码错误 +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟 +user.password.delete=对不起,您的账号已被删除 +user.blocked=用户已封禁,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 + +length.not.valid=长度必须在{min}到{max}个字符之间 + +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.password.not.valid=* 5-50个字符 + +user.email.not.valid=邮箱格式错误 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 + +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 + +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] diff --git a/ruoyi-admin/src/main/resources/logback.xml b/ruoyi-common/src/main/resources/logback.xml similarity index 96% rename from ruoyi-admin/src/main/resources/logback.xml rename to ruoyi-common/src/main/resources/logback.xml index d69a57207..a360583fa 100644 --- a/ruoyi-admin/src/main/resources/logback.xml +++ b/ruoyi-common/src/main/resources/logback.xml @@ -1,93 +1,93 @@ - - - - - - - - - - - ${log.pattern} - - - - - - ${log.path}/sys-info.log - - - - ${log.path}/sys-info.%d{yyyy-MM-dd}.log - - 60 - - - ${log.pattern} - - - - INFO - - ACCEPT - - DENY - - - - - ${log.path}/sys-error.log - - - - ${log.path}/sys-error.%d{yyyy-MM-dd}.log - - 60 - - - ${log.pattern} - - - - ERROR - - ACCEPT - - DENY - - - - - - ${log.path}/sys-user.log - - - ${log.path}/sys-user.%d{yyyy-MM-dd}.log - - 60 - - - ${log.pattern} - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + ${log.pattern} + + + + + + ${log.path}/sys-info.log + + + + ${log.path}/sys-info.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + + ${log.path}/sys-error.log + + + + ${log.path}/sys-error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + ${log.path}/sys-user.log + + + ${log.path}/sys-user.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-ui/src/api/monitor/online.js b/ruoyi-ui/src/api/system/session.js similarity index 74% rename from ruoyi-ui/src/api/monitor/online.js rename to ruoyi-ui/src/api/system/session.js index 288ebe029..dee070995 100644 --- a/ruoyi-ui/src/api/monitor/online.js +++ b/ruoyi-ui/src/api/system/session.js @@ -1,18 +1,18 @@ -import request from '@/utils/request' - -// 查询在线用户列表 -export function list(query) { - return request({ - url: '/monitor/online/list', - method: 'get', - params: query - }) -} - -// 强退用户 -export function forceLogout(tokenId) { - return request({ - url: '/monitor/online/' + tokenId, - method: 'delete' - }) -} +import request from '@/utils/request' + +// 查询在线用户列表 +export function list(query) { + return request({ + url: '/system/user-session/page', + method: 'get', + params: query + }) +} + +// 强退用户 +export function forceLogout(tokenId) { + return request({ + url: '/system/user-session/delete?id=' + tokenId, + method: 'delete' + }) +} diff --git a/ruoyi-ui/src/views/monitor/online/index.vue b/ruoyi-ui/src/views/system/session/index.vue similarity index 62% rename from ruoyi-ui/src/views/monitor/online/index.vue rename to ruoyi-ui/src/views/system/session/index.vue index 0dc6e98c3..5c0be114a 100644 --- a/ruoyi-ui/src/views/monitor/online/index.vue +++ b/ruoyi-ui/src/views/system/session/index.vue @@ -1,128 +1,121 @@ - - - - + + + + diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/SysUserSessionController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/SysUserSessionController.java index f366e0d29..4401dd52d 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/SysUserSessionController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/SysUserSessionController.java @@ -4,8 +4,14 @@ import cn.iocoder.dashboard.common.pojo.CommonResult; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageItemRespVO; import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO; +import cn.iocoder.dashboard.modules.system.convert.auth.SysUserSessionConvert; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysDeptDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService; +import cn.iocoder.dashboard.modules.system.service.dept.SysDeptService; +import cn.iocoder.dashboard.modules.system.service.user.SysUserService; +import cn.iocoder.dashboard.util.collection.MapUtils; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; @@ -14,26 +20,50 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import static cn.iocoder.dashboard.common.pojo.CommonResult.success; +import static cn.iocoder.dashboard.util.collection.CollectionUtils.convertList; @Api("用户 Session API") @RestController -@RequestMapping("/user-session") +@RequestMapping("/system/user-session") public class SysUserSessionController { @Resource private SysUserSessionService userSessionService; + @Resource + private SysUserService userService; + @Resource + private SysDeptService deptService; @ApiOperation("获得 Session 分页列表") @PreAuthorize("@ss.hasPermission('system:user-session:page')") @GetMapping("/page") public CommonResult> getUserSessionPage(@Validated SysUserSessionPageReqVO reqVO) { // 获得 Session 分页 - PageResult sessionPage = userSessionService.getUserSessionPage(reqVO); + PageResult pageResult = userSessionService.getUserSessionPage(reqVO); - // - return null; + // 获得拼接需要的数据 + Map userMap = userService.getUserMap( + convertList(pageResult.getList(), SysUserSessionDO::getUserId)); + Map deptMap = deptService.getDeptMap( + convertList(userMap.values(), SysUserDO::getDeptId)); + // 拼接结果返回 + List sessionList = new ArrayList<>(pageResult.getList().size()); + pageResult.getList().forEach(session -> { + SysUserSessionPageItemRespVO respVO = SysUserSessionConvert.INSTANCE.convert(session); + sessionList.add(respVO); + // 设置用户账号 + MapUtils.findAndThen(userMap, session.getUserId(), user -> { + respVO.setUsername(user.getUsername()); + // 设置用户部门 + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> respVO.setDeptName(dept.getName())); + }); + }); + return success(new PageResult<>(sessionList, pageResult.getTotal())); } @ApiOperation("删除 Session") diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/session/SysUserSessionPageItemRespVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/session/SysUserSessionPageItemRespVO.java index adf1f9459..3cc1e09af 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/session/SysUserSessionPageItemRespVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/session/SysUserSessionPageItemRespVO.java @@ -8,6 +8,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import java.util.Date; + @ApiModel(value = "用户在线 Session Response VO", description = "相比用户基本信息来说,会多部门、用户账号等信息") @Data @NoArgsConstructor @@ -25,7 +27,7 @@ public class SysUserSessionPageItemRespVO extends PageParam { private String userAgent; @ApiModelProperty(value = "登陆时间", required = true) - private String createTime; + private Date createTime; @ApiModelProperty(value = "用户账号", required = true, example = "yudao") private String username; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/session/SysUserSessionPageReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/session/SysUserSessionPageReqVO.java index 2b27b867f..3a2fca733 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/session/SysUserSessionPageReqVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/session/SysUserSessionPageReqVO.java @@ -14,7 +14,6 @@ import javax.validation.constraints.NotEmpty; public class SysUserSessionPageReqVO extends PageParam { @ApiModelProperty(value = "用户 IP", example = "127.0.0.1", notes = "模糊匹配") - @NotEmpty(message = "用户 IP 不能为空") private String userIp; @ApiModelProperty(value = "用户账号", example = "yudao", notes = "模糊匹配") diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/auth/SysUserSessionConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/auth/SysUserSessionConvert.java new file mode 100644 index 000000000..a8b65675f --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/auth/SysUserSessionConvert.java @@ -0,0 +1,16 @@ +package cn.iocoder.dashboard.modules.system.convert.auth; + +import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageItemRespVO; +import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserPageItemRespVO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface SysUserSessionConvert { + + SysUserSessionConvert INSTANCE = Mappers.getMapper(SysUserSessionConvert.class); + + SysUserSessionPageItemRespVO convert(SysUserSessionDO session); + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/auth/SysUserSessionMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/auth/SysUserSessionMapper.java index 51aed9dbb..310d30df4 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/auth/SysUserSessionMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/auth/SysUserSessionMapper.java @@ -1,9 +1,21 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dao.auth; +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; +import java.util.Collection; + @Mapper -public interface SysUserSessionMapper extends BaseMapper { +public interface SysUserSessionMapper extends BaseMapperX { + + default PageResult selectPage(SysUserSessionPageReqVO reqVO, Collection userIds) { + return selectPage(reqVO, new QueryWrapperX() + .inIfPresent("user_id", userIds) + .likeIfPresent("user_ip", reqVO.getUserIp())); + } + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/user/SysUserMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/user/SysUserMapper.java index 933bdde00..c9ea4a629 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/user/SysUserMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/user/SysUserMapper.java @@ -48,5 +48,9 @@ public interface SysUserMapper extends BaseMapperX { return selectList(new QueryWrapperX().like("nickname", nickname)); } + default List selectListByUsername(String username) { + return selectList(new QueryWrapperX().like("username", username)); + } + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/auth/SysUserSessionDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/auth/SysUserSessionDO.java index 1efda9b85..f8e229619 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/auth/SysUserSessionDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/auth/SysUserSessionDO.java @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth; import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.dashboard.framework.security.core.LoginUser; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; +import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Builder; @@ -27,7 +28,7 @@ public class SysUserSessionDO extends BaseDO { /** * 会话编号, 即 sessionId */ - @TableId + @TableId(type = IdType.INPUT) private String id; /** * 用户编号 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/dao/auth/SysLoginUserRedisDAO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/dao/auth/SysLoginUserRedisDAO.java index 0b54d4535..e5f517e40 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/dao/auth/SysLoginUserRedisDAO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/dao/auth/SysLoginUserRedisDAO.java @@ -30,8 +30,8 @@ public class SysLoginUserRedisDAO { stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(loginUser), LOGIN_USER.getTimeout()); } - public void delete(String accessToken) { - String redisKey = formatKey(accessToken); + public void delete(String sessionId) { + String redisKey = formatKey(sessionId); stringRedisTemplate.delete(redisKey); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/job/package-info.java b/src/main/java/cn/iocoder/dashboard/modules/system/job/package-info.java new file mode 100644 index 000000000..de704997d --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/job/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.dashboard.modules.system.job; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysUserSessionServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysUserSessionServiceImpl.java index 6dda624c4..25c1da1e5 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysUserSessionServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysUserSessionServiceImpl.java @@ -1,19 +1,26 @@ package cn.iocoder.dashboard.modules.system.service.auth.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.security.config.SecurityProperties; import cn.iocoder.dashboard.framework.security.core.LoginUser; import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.auth.SysUserSessionMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO; import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService; +import cn.iocoder.dashboard.modules.system.service.user.SysUserService; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.util.Collection; import java.util.Date; +import static cn.iocoder.dashboard.util.collection.CollectionUtils.convertSet; + /** * 在线用户 Session Service 实现类 * @@ -27,10 +34,12 @@ public class SysUserSessionServiceImpl implements SysUserSessionService { @Resource private SysLoginUserRedisDAO loginUserRedisDAO; - @Resource private SysUserSessionMapper userSessionMapper; + @Resource + private SysUserService userService; + @Override public String createUserSession(LoginUser loginUser, String userIp, String userAgent) { // 生成 Session 编号 @@ -39,8 +48,8 @@ public class SysUserSessionServiceImpl implements SysUserSessionService { loginUser.setUpdateTime(new Date()); loginUserRedisDAO.set(sessionId, loginUser); // 写入 DB 中 - SysUserSessionDO userSession = SysUserSessionDO.builder().userId(loginUser.getId()) - .userIp(userIp).userAgent(userAgent).build(); + SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId) + .userId(loginUser.getId()).userIp(userIp).userAgent(userAgent).build(); userSessionMapper.insert(userSession); // 返回 Session 编号 return sessionId; @@ -59,7 +68,10 @@ public class SysUserSessionServiceImpl implements SysUserSessionService { @Override public void deleteUserSession(String sessionId) { - + // 删除 Redis 缓存 + loginUserRedisDAO.delete(sessionId); + // 删除 DB 记录 + userSessionMapper.deleteById(sessionId); } @Override @@ -74,7 +86,15 @@ public class SysUserSessionServiceImpl implements SysUserSessionService { @Override public PageResult getUserSessionPage(SysUserSessionPageReqVO reqVO) { - return null; + // 处理基于用户昵称的查询 + Collection userIds = null; + if (StrUtil.isNotEmpty(reqVO.getUsername())) { + userIds = convertSet(userService.listUsersByUsername(reqVO.getUsername()), SysUserDO::getId); + if (CollUtil.isEmpty(userIds)) { + return PageResult.empty(); + } + } + return userSessionMapper.selectPage(reqVO, userIds); } /** diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserService.java index 288c14dee..ab6ee758a 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserService.java @@ -79,6 +79,14 @@ public interface SysUserService { */ List listUsersByNickname(String nickname); + /** + * 获得用户列表,基于用户账号模糊匹配 + * + * @param username 用户账号 + * @return 用户列表 + */ + List listUsersByUsername(String username); + /** * 创建用户 * diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImpl.java index af8dd1a64..efc202f92 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImpl.java @@ -92,6 +92,11 @@ public class SysUserServiceImpl implements SysUserService { return userMapper.selectListByNickname(nickname); } + @Override + public List listUsersByUsername(String username) { + return userMapper.selectListByUsername(username); + } + /** * 获得部门条件:查询指定部门的子部门编号们,包括自身 * diff --git a/src/main/java/cn/iocoder/dashboard/util/collection/CollectionUtils.java b/src/main/java/cn/iocoder/dashboard/util/collection/CollectionUtils.java index 497c40780..5142b7926 100644 --- a/src/main/java/cn/iocoder/dashboard/util/collection/CollectionUtils.java +++ b/src/main/java/cn/iocoder/dashboard/util/collection/CollectionUtils.java @@ -26,35 +26,35 @@ public class CollectionUtils { return from.stream().filter(predicate).collect(Collectors.toList()); } - public static List convertList(List from, Function func) { + public static List convertList(Collection from, Function func) { if (CollUtil.isEmpty(from)) { return new ArrayList<>(); } return from.stream().map(func).collect(Collectors.toList()); } - public static Set convertSet(List from, Function func) { + public static Set convertSet(Collection from, Function func) { if (CollUtil.isEmpty(from)) { return new HashSet<>(); } return from.stream().map(func).collect(Collectors.toSet()); } - public static Map convertMap(List from, Function keyFunc) { + public static Map convertMap(Collection from, Function keyFunc) { if (CollUtil.isEmpty(from)) { return new HashMap<>(); } return from.stream().collect(Collectors.toMap(keyFunc, item -> item)); } - public static Map convertMap(List from, Function keyFunc, Function valueFunc) { + public static Map convertMap(Collection from, Function keyFunc, Function valueFunc) { if (CollUtil.isEmpty(from)) { return new HashMap<>(); } return from.stream().collect(Collectors.toMap(keyFunc, valueFunc)); } - public static Map> convertMultiMap(List from, Function keyFunc) { + public static Map> convertMultiMap(Collection from, Function keyFunc) { if (CollUtil.isEmpty(from)) { return new HashMap<>(); } @@ -62,7 +62,7 @@ public class CollectionUtils { Collectors.mapping(t -> t, Collectors.toList()))); } - public static Map> convertMultiMap(List from, Function keyFunc, Function valueFunc) { + public static Map> convertMultiMap(Collection from, Function keyFunc, Function valueFunc) { if (CollUtil.isEmpty(from)) { return new HashMap<>(); } @@ -71,7 +71,7 @@ public class CollectionUtils { } // 暂时没想好名字,先以 2 结尾噶 - public static Map> convertMultiMap2(List from, Function keyFunc, Function valueFunc) { + public static Map> convertMultiMap2(Collection from, Function keyFunc, Function valueFunc) { if (CollUtil.isEmpty(from)) { return new HashMap<>(); }