Commit 753c7678ee5a3da612e0b570c21aecd3447130c3
1 parent
ab94fe2d
完成主要在线 session 的功能
Showing
34 changed files
with
1349 additions
and
1260 deletions
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SwaggerController.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/SwaggerController.java
| @@ -8,17 +8,15 @@ import com.ruoyi.common.core.controller.BaseController; | @@ -8,17 +8,15 @@ import com.ruoyi.common.core.controller.BaseController; | ||
| 8 | 8 | ||
| 9 | /** | 9 | /** |
| 10 | * swagger 接口 | 10 | * swagger 接口 |
| 11 | - * | 11 | + * |
| 12 | * @author ruoyi | 12 | * @author ruoyi |
| 13 | */ | 13 | */ |
| 14 | @Controller | 14 | @Controller |
| 15 | @RequestMapping("/tool/swagger") | 15 | @RequestMapping("/tool/swagger") |
| 16 | -public class SwaggerController extends BaseController | ||
| 17 | -{ | 16 | +public class SwaggerController extends BaseController { |
| 18 | @PreAuthorize("@ss.hasPermi('tool:swagger:view')") | 17 | @PreAuthorize("@ss.hasPermi('tool:swagger:view')") |
| 19 | @GetMapping() | 18 | @GetMapping() |
| 20 | - public String index() | ||
| 21 | - { | 19 | + public String index() { |
| 22 | return redirect("/swagger-ui.html"); | 20 | return redirect("/swagger-ui.html"); |
| 23 | } | 21 | } |
| 24 | } | 22 | } |
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScopeAspect.java
| 1 | -package com.ruoyi.framework.aspectj; | ||
| 2 | - | ||
| 3 | -import java.lang.reflect.Method; | ||
| 4 | - | ||
| 5 | -import org.aspectj.lang.JoinPoint; | ||
| 6 | -import org.aspectj.lang.Signature; | ||
| 7 | -import org.aspectj.lang.annotation.Aspect; | ||
| 8 | -import org.aspectj.lang.annotation.Before; | ||
| 9 | -import org.aspectj.lang.annotation.Pointcut; | ||
| 10 | -import org.aspectj.lang.reflect.MethodSignature; | ||
| 11 | -import org.springframework.stereotype.Component; | ||
| 12 | -import com.ruoyi.common.annotation.DataScope; | ||
| 13 | -import com.ruoyi.common.core.domain.BaseEntity; | ||
| 14 | -import com.ruoyi.common.core.domain.entity.SysRole; | ||
| 15 | -import com.ruoyi.common.core.domain.entity.SysUser; | ||
| 16 | -import com.ruoyi.common.core.domain.model.LoginUser; | ||
| 17 | -import com.ruoyi.common.utils.ServletUtils; | ||
| 18 | -import com.ruoyi.common.utils.StringUtils; | ||
| 19 | -import com.ruoyi.common.utils.spring.SpringUtils; | ||
| 20 | -import com.ruoyi.framework.web.service.TokenService; | ||
| 21 | - | ||
| 22 | -/** | ||
| 23 | - * 数据过滤处理 | ||
| 24 | - * | ||
| 25 | - * @author ruoyi | ||
| 26 | - */ | ||
| 27 | -@Aspect | ||
| 28 | -@Component | ||
| 29 | -public class DataScopeAspect { | ||
| 30 | - /** | ||
| 31 | - * 全部数据权限 | ||
| 32 | - */ | ||
| 33 | - public static final String DATA_SCOPE_ALL = "1"; | ||
| 34 | - | ||
| 35 | - /** | ||
| 36 | - * 自定数据权限 | ||
| 37 | - */ | ||
| 38 | - public static final String DATA_SCOPE_CUSTOM = "2"; | ||
| 39 | - | ||
| 40 | - /** | ||
| 41 | - * 部门数据权限 | ||
| 42 | - */ | ||
| 43 | - public static final String DATA_SCOPE_DEPT = "3"; | ||
| 44 | - | ||
| 45 | - /** | ||
| 46 | - * 部门及以下数据权限 | ||
| 47 | - */ | ||
| 48 | - public static final String DATA_SCOPE_DEPT_AND_CHILD = "4"; | ||
| 49 | - | ||
| 50 | - /** | ||
| 51 | - * 仅本人数据权限 | ||
| 52 | - */ | ||
| 53 | - public static final String DATA_SCOPE_SELF = "5"; | ||
| 54 | - | ||
| 55 | - /** | ||
| 56 | - * 数据权限过滤关键字 | ||
| 57 | - */ | ||
| 58 | - public static final String DATA_SCOPE = "dataScope"; | ||
| 59 | - | ||
| 60 | - // 配置织入点 | ||
| 61 | - @Pointcut("@annotation(com.ruoyi.common.annotation.DataScope)") | ||
| 62 | - public void dataScopePointCut() { | ||
| 63 | - } | ||
| 64 | - | ||
| 65 | - @Before("dataScopePointCut()") | ||
| 66 | - public void doBefore(JoinPoint point) throws Throwable { | ||
| 67 | - handleDataScope(point); | ||
| 68 | - } | ||
| 69 | - | ||
| 70 | - protected void handleDataScope(final JoinPoint joinPoint) { | ||
| 71 | - // 获得注解 | ||
| 72 | - DataScope controllerDataScope = getAnnotationLog(joinPoint); | ||
| 73 | - if (controllerDataScope == null) { | ||
| 74 | - return; | ||
| 75 | - } | ||
| 76 | - // 获取当前的用户 | ||
| 77 | - LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest()); | ||
| 78 | - if (StringUtils.isNotNull(loginUser)) { | ||
| 79 | - SysUser currentUser = loginUser.getUser(); | ||
| 80 | - // 如果是超级管理员,则不过滤数据 | ||
| 81 | - if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) { | ||
| 82 | - dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), | ||
| 83 | - controllerDataScope.userAlias()); | ||
| 84 | - } | ||
| 85 | - } | ||
| 86 | - } | ||
| 87 | - | ||
| 88 | - /** | ||
| 89 | - * 数据范围过滤 | ||
| 90 | - * | ||
| 91 | - * @param joinPoint 切点 | ||
| 92 | - * @param user 用户 | ||
| 93 | - * @param userAlias 别名 | ||
| 94 | - */ | ||
| 95 | - public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias) { | ||
| 96 | - StringBuilder sqlString = new StringBuilder(); | ||
| 97 | - | ||
| 98 | - for (SysRole role : user.getRoles()) { | ||
| 99 | - String dataScope = role.getDataScope(); | ||
| 100 | - if (DATA_SCOPE_ALL.equals(dataScope)) { | ||
| 101 | - sqlString = new StringBuilder(); | ||
| 102 | - break; | ||
| 103 | - } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) { | ||
| 104 | - sqlString.append(StringUtils.format( | ||
| 105 | - " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, | ||
| 106 | - role.getRoleId())); | ||
| 107 | - } else if (DATA_SCOPE_DEPT.equals(dataScope)) { | ||
| 108 | - sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId())); | ||
| 109 | - } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) { | ||
| 110 | - sqlString.append(StringUtils.format( | ||
| 111 | - " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", | ||
| 112 | - deptAlias, user.getDeptId(), user.getDeptId())); | ||
| 113 | - } else if (DATA_SCOPE_SELF.equals(dataScope)) { | ||
| 114 | - if (StringUtils.isNotBlank(userAlias)) { | ||
| 115 | - sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId())); | ||
| 116 | - } else { | ||
| 117 | - // 数据权限为仅本人且没有userAlias别名不查询任何数据 | ||
| 118 | - sqlString.append(" OR 1=0 "); | ||
| 119 | - } | ||
| 120 | - } | ||
| 121 | - } | ||
| 122 | - | ||
| 123 | - if (StringUtils.isNotBlank(sqlString.toString())) { | ||
| 124 | - Object params = joinPoint.getArgs()[0]; | ||
| 125 | - if (StringUtils.isNotNull(params) && params instanceof BaseEntity) { | ||
| 126 | - BaseEntity baseEntity = (BaseEntity) params; | ||
| 127 | - baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")"); | ||
| 128 | - } | ||
| 129 | - } | ||
| 130 | - } | ||
| 131 | - | ||
| 132 | - /** | ||
| 133 | - * 是否存在注解,如果存在就获取 | ||
| 134 | - */ | ||
| 135 | - private DataScope getAnnotationLog(JoinPoint joinPoint) { | ||
| 136 | - Signature signature = joinPoint.getSignature(); | ||
| 137 | - MethodSignature methodSignature = (MethodSignature) signature; | ||
| 138 | - Method method = methodSignature.getMethod(); | ||
| 139 | - | ||
| 140 | - if (method != null) { | ||
| 141 | - return method.getAnnotation(DataScope.class); | ||
| 142 | - } | ||
| 143 | - return null; | ||
| 144 | - } | ||
| 145 | -} | 1 | +package com.ruoyi.framework.aspectj; |
| 2 | + | ||
| 3 | +import java.lang.reflect.Method; | ||
| 4 | + | ||
| 5 | +import org.aspectj.lang.JoinPoint; | ||
| 6 | +import org.aspectj.lang.Signature; | ||
| 7 | +import org.aspectj.lang.annotation.Aspect; | ||
| 8 | +import org.aspectj.lang.annotation.Before; | ||
| 9 | +import org.aspectj.lang.annotation.Pointcut; | ||
| 10 | +import org.aspectj.lang.reflect.MethodSignature; | ||
| 11 | +import org.springframework.stereotype.Component; | ||
| 12 | +import com.ruoyi.common.annotation.DataScope; | ||
| 13 | +import com.ruoyi.common.core.domain.BaseEntity; | ||
| 14 | +import com.ruoyi.common.core.domain.entity.SysRole; | ||
| 15 | +import com.ruoyi.common.core.domain.entity.SysUser; | ||
| 16 | +import com.ruoyi.common.core.domain.model.LoginUser; | ||
| 17 | +import com.ruoyi.common.utils.ServletUtils; | ||
| 18 | +import com.ruoyi.common.utils.StringUtils; | ||
| 19 | +import com.ruoyi.common.utils.spring.SpringUtils; | ||
| 20 | +import com.ruoyi.framework.web.service.TokenService; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * 数据过滤处理 | ||
| 24 | + * | ||
| 25 | + * @author ruoyi | ||
| 26 | + */ | ||
| 27 | +@Aspect | ||
| 28 | +@Component | ||
| 29 | +public class DataScopeAspect { | ||
| 30 | + /** | ||
| 31 | + * 全部数据权限 | ||
| 32 | + */ | ||
| 33 | + public static final String DATA_SCOPE_ALL = "1"; | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * 自定数据权限 | ||
| 37 | + */ | ||
| 38 | + public static final String DATA_SCOPE_CUSTOM = "2"; | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * 部门数据权限 | ||
| 42 | + */ | ||
| 43 | + public static final String DATA_SCOPE_DEPT = "3"; | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * 部门及以下数据权限 | ||
| 47 | + */ | ||
| 48 | + public static final String DATA_SCOPE_DEPT_AND_CHILD = "4"; | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * 仅本人数据权限 | ||
| 52 | + */ | ||
| 53 | + public static final String DATA_SCOPE_SELF = "5"; | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * 数据权限过滤关键字 | ||
| 57 | + */ | ||
| 58 | + public static final String DATA_SCOPE = "dataScope"; | ||
| 59 | + | ||
| 60 | + // 配置织入点 | ||
| 61 | + @Pointcut("@annotation(com.ruoyi.common.annotation.DataScope)") | ||
| 62 | + public void dataScopePointCut() { | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + @Before("dataScopePointCut()") | ||
| 66 | + public void doBefore(JoinPoint point) throws Throwable { | ||
| 67 | + handleDataScope(point); | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + protected void handleDataScope(final JoinPoint joinPoint) { | ||
| 71 | + // 获得注解 | ||
| 72 | + DataScope controllerDataScope = getAnnotationLog(joinPoint); | ||
| 73 | + if (controllerDataScope == null) { | ||
| 74 | + return; | ||
| 75 | + } | ||
| 76 | + // 获取当前的用户 | ||
| 77 | + LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest()); | ||
| 78 | + if (StringUtils.isNotNull(loginUser)) { | ||
| 79 | + SysUser currentUser = loginUser.getUser(); | ||
| 80 | + // 如果是超级管理员,则不过滤数据 | ||
| 81 | + if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) { | ||
| 82 | + dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), | ||
| 83 | + controllerDataScope.userAlias()); | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + /** | ||
| 89 | + * 数据范围过滤 | ||
| 90 | + * | ||
| 91 | + * @param joinPoint 切点 | ||
| 92 | + * @param user 用户 | ||
| 93 | + * @param userAlias 别名 | ||
| 94 | + */ | ||
| 95 | + public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias) { | ||
| 96 | + StringBuilder sqlString = new StringBuilder(); | ||
| 97 | + | ||
| 98 | + for (SysRole role : user.getRoles()) { | ||
| 99 | + String dataScope = role.getDataScope(); | ||
| 100 | + if (DATA_SCOPE_ALL.equals(dataScope)) { | ||
| 101 | + sqlString = new StringBuilder(); | ||
| 102 | + break; | ||
| 103 | + } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) { | ||
| 104 | + sqlString.append(StringUtils.format( | ||
| 105 | + " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, | ||
| 106 | + role.getRoleId())); | ||
| 107 | + } else if (DATA_SCOPE_DEPT.equals(dataScope)) { | ||
| 108 | + sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId())); | ||
| 109 | + } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) { | ||
| 110 | + sqlString.append(StringUtils.format( | ||
| 111 | + " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", | ||
| 112 | + deptAlias, user.getDeptId(), user.getDeptId())); | ||
| 113 | + } else if (DATA_SCOPE_SELF.equals(dataScope)) { | ||
| 114 | + if (StringUtils.isNotBlank(userAlias)) { | ||
| 115 | + sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId())); | ||
| 116 | + } else { | ||
| 117 | + // 数据权限为仅本人且没有userAlias别名不查询任何数据 | ||
| 118 | + sqlString.append(" OR 1=0 "); | ||
| 119 | + } | ||
| 120 | + } | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + if (StringUtils.isNotBlank(sqlString.toString())) { | ||
| 124 | + Object params = joinPoint.getArgs()[0]; | ||
| 125 | + if (StringUtils.isNotNull(params) && params instanceof BaseEntity) { | ||
| 126 | + BaseEntity baseEntity = (BaseEntity) params; | ||
| 127 | + baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")"); | ||
| 128 | + } | ||
| 129 | + } | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + /** | ||
| 133 | + * 是否存在注解,如果存在就获取 | ||
| 134 | + */ | ||
| 135 | + private DataScope getAnnotationLog(JoinPoint joinPoint) { | ||
| 136 | + Signature signature = joinPoint.getSignature(); | ||
| 137 | + MethodSignature methodSignature = (MethodSignature) signature; | ||
| 138 | + Method method = methodSignature.getMethod(); | ||
| 139 | + | ||
| 140 | + if (method != null) { | ||
| 141 | + return method.getAnnotation(DataScope.class); | ||
| 142 | + } | ||
| 143 | + return null; | ||
| 144 | + } | ||
| 145 | +} |
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSourceAspect.java
| 1 | -package com.ruoyi.framework.aspectj; | ||
| 2 | - | ||
| 3 | -import java.util.Objects; | ||
| 4 | - | ||
| 5 | -import org.aspectj.lang.ProceedingJoinPoint; | ||
| 6 | -import org.aspectj.lang.annotation.Around; | ||
| 7 | -import org.aspectj.lang.annotation.Aspect; | ||
| 8 | -import org.aspectj.lang.annotation.Pointcut; | ||
| 9 | -import org.aspectj.lang.reflect.MethodSignature; | ||
| 10 | -import org.slf4j.Logger; | ||
| 11 | -import org.slf4j.LoggerFactory; | ||
| 12 | -import org.springframework.core.annotation.AnnotationUtils; | ||
| 13 | -import org.springframework.core.annotation.Order; | ||
| 14 | -import org.springframework.stereotype.Component; | ||
| 15 | -import com.ruoyi.common.annotation.DataSource; | ||
| 16 | -import com.ruoyi.common.utils.StringUtils; | ||
| 17 | -import com.ruoyi.framework.datasource.DynamicDataSourceContextHolder; | ||
| 18 | - | ||
| 19 | -/** | ||
| 20 | - * 多数据源处理 | ||
| 21 | - * | ||
| 22 | - * @author ruoyi | ||
| 23 | - */ | ||
| 24 | -@Aspect | ||
| 25 | -@Order(1) | ||
| 26 | -@Component | ||
| 27 | -public class DataSourceAspect { | ||
| 28 | - protected Logger logger = LoggerFactory.getLogger(getClass()); | ||
| 29 | - | ||
| 30 | - @Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)" | ||
| 31 | - + "|| @within(com.ruoyi.common.annotation.DataSource)") | ||
| 32 | - public void dsPointCut() { | ||
| 33 | - | ||
| 34 | - } | ||
| 35 | - | ||
| 36 | - @Around("dsPointCut()") | ||
| 37 | - public Object around(ProceedingJoinPoint point) throws Throwable { | ||
| 38 | - DataSource dataSource = getDataSource(point); | ||
| 39 | - | ||
| 40 | - if (StringUtils.isNotNull(dataSource)) { | ||
| 41 | - DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name()); | ||
| 42 | - } | ||
| 43 | - | ||
| 44 | - try { | ||
| 45 | - return point.proceed(); | ||
| 46 | - } finally { | ||
| 47 | - // 销毁数据源 在执行方法之后 | ||
| 48 | - DynamicDataSourceContextHolder.clearDataSourceType(); | ||
| 49 | - } | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - /** | ||
| 53 | - * 获取需要切换的数据源 | ||
| 54 | - */ | ||
| 55 | - public DataSource getDataSource(ProceedingJoinPoint point) { | ||
| 56 | - MethodSignature signature = (MethodSignature) point.getSignature(); | ||
| 57 | - DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class); | ||
| 58 | - if (Objects.nonNull(dataSource)) { | ||
| 59 | - return dataSource; | ||
| 60 | - } | ||
| 61 | - | ||
| 62 | - return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class); | ||
| 63 | - } | ||
| 64 | -} | 1 | +package com.ruoyi.framework.aspectj; |
| 2 | + | ||
| 3 | +import java.util.Objects; | ||
| 4 | + | ||
| 5 | +import org.aspectj.lang.ProceedingJoinPoint; | ||
| 6 | +import org.aspectj.lang.annotation.Around; | ||
| 7 | +import org.aspectj.lang.annotation.Aspect; | ||
| 8 | +import org.aspectj.lang.annotation.Pointcut; | ||
| 9 | +import org.aspectj.lang.reflect.MethodSignature; | ||
| 10 | +import org.slf4j.Logger; | ||
| 11 | +import org.slf4j.LoggerFactory; | ||
| 12 | +import org.springframework.core.annotation.AnnotationUtils; | ||
| 13 | +import org.springframework.core.annotation.Order; | ||
| 14 | +import org.springframework.stereotype.Component; | ||
| 15 | +import com.ruoyi.common.annotation.DataSource; | ||
| 16 | +import com.ruoyi.common.utils.StringUtils; | ||
| 17 | +import com.ruoyi.framework.datasource.DynamicDataSourceContextHolder; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * 多数据源处理 | ||
| 21 | + * | ||
| 22 | + * @author ruoyi | ||
| 23 | + */ | ||
| 24 | +@Aspect | ||
| 25 | +@Order(1) | ||
| 26 | +@Component | ||
| 27 | +public class DataSourceAspect { | ||
| 28 | + protected Logger logger = LoggerFactory.getLogger(getClass()); | ||
| 29 | + | ||
| 30 | + @Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)" | ||
| 31 | + + "|| @within(com.ruoyi.common.annotation.DataSource)") | ||
| 32 | + public void dsPointCut() { | ||
| 33 | + | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + @Around("dsPointCut()") | ||
| 37 | + public Object around(ProceedingJoinPoint point) throws Throwable { | ||
| 38 | + DataSource dataSource = getDataSource(point); | ||
| 39 | + | ||
| 40 | + if (StringUtils.isNotNull(dataSource)) { | ||
| 41 | + DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name()); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + try { | ||
| 45 | + return point.proceed(); | ||
| 46 | + } finally { | ||
| 47 | + // 销毁数据源 在执行方法之后 | ||
| 48 | + DynamicDataSourceContextHolder.clearDataSourceType(); | ||
| 49 | + } | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * 获取需要切换的数据源 | ||
| 54 | + */ | ||
| 55 | + public DataSource getDataSource(ProceedingJoinPoint point) { | ||
| 56 | + MethodSignature signature = (MethodSignature) point.getSignature(); | ||
| 57 | + DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class); | ||
| 58 | + if (Objects.nonNull(dataSource)) { | ||
| 59 | + return dataSource; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class); | ||
| 63 | + } | ||
| 64 | +} |
ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSourceType.java
| 1 | -package com.ruoyi.common.enums; | ||
| 2 | - | ||
| 3 | -/** | ||
| 4 | - * 数据源 | ||
| 5 | - * | ||
| 6 | - * @author ruoyi | ||
| 7 | - */ | ||
| 8 | -public enum DataSourceType | ||
| 9 | -{ | ||
| 10 | - /** | ||
| 11 | - * 主库 | ||
| 12 | - */ | ||
| 13 | - MASTER, | ||
| 14 | - | ||
| 15 | - /** | ||
| 16 | - * 从库 | ||
| 17 | - */ | ||
| 18 | - SLAVE | ||
| 19 | -} | 1 | +package com.ruoyi.common.enums; |
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 数据源 | ||
| 5 | + * | ||
| 6 | + * @author ruoyi | ||
| 7 | + */ | ||
| 8 | +public enum DataSourceType | ||
| 9 | +{ | ||
| 10 | + /** | ||
| 11 | + * 主库 | ||
| 12 | + */ | ||
| 13 | + MASTER, | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 从库 | ||
| 17 | + */ | ||
| 18 | + SLAVE | ||
| 19 | +} |
ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/annotation/DynamicDataSource.java
| 1 | -package com.ruoyi.framework.datasource; | ||
| 2 | - | ||
| 3 | -import java.util.Map; | ||
| 4 | -import javax.sql.DataSource; | ||
| 5 | - | ||
| 6 | -import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; | ||
| 7 | - | ||
| 8 | -/** | ||
| 9 | - * 动态数据源 | ||
| 10 | - * | ||
| 11 | - * @author ruoyi | ||
| 12 | - */ | ||
| 13 | -public class DynamicDataSource extends AbstractRoutingDataSource { | ||
| 14 | - public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) { | ||
| 15 | - super.setDefaultTargetDataSource(defaultTargetDataSource); | ||
| 16 | - super.setTargetDataSources(targetDataSources); | ||
| 17 | - super.afterPropertiesSet(); | ||
| 18 | - } | ||
| 19 | - | ||
| 20 | - @Override | ||
| 21 | - protected Object determineCurrentLookupKey() { | ||
| 22 | - return DynamicDataSourceContextHolder.getDataSourceType(); | ||
| 23 | - } | ||
| 24 | -} | 1 | +package com.ruoyi.framework.datasource; |
| 2 | + | ||
| 3 | +import java.util.Map; | ||
| 4 | +import javax.sql.DataSource; | ||
| 5 | + | ||
| 6 | +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 动态数据源 | ||
| 10 | + * | ||
| 11 | + * @author ruoyi | ||
| 12 | + */ | ||
| 13 | +public class DynamicDataSource extends AbstractRoutingDataSource { | ||
| 14 | + public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) { | ||
| 15 | + super.setDefaultTargetDataSource(defaultTargetDataSource); | ||
| 16 | + super.setTargetDataSources(targetDataSources); | ||
| 17 | + super.afterPropertiesSet(); | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + @Override | ||
| 21 | + protected Object determineCurrentLookupKey() { | ||
| 22 | + return DynamicDataSourceContextHolder.getDataSourceType(); | ||
| 23 | + } | ||
| 24 | +} |
ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/annotation/DynamicDataSourceContextHolder.java
| 1 | -package com.ruoyi.framework.datasource; | ||
| 2 | - | ||
| 3 | -import org.slf4j.Logger; | ||
| 4 | -import org.slf4j.LoggerFactory; | ||
| 5 | - | ||
| 6 | -/** | ||
| 7 | - * 数据源切换处理 | ||
| 8 | - * | ||
| 9 | - * @author ruoyi | ||
| 10 | - */ | ||
| 11 | -public class DynamicDataSourceContextHolder { | ||
| 12 | - public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class); | ||
| 13 | - | ||
| 14 | - /** | ||
| 15 | - * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本, | ||
| 16 | - * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 | ||
| 17 | - */ | ||
| 18 | - private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>(); | ||
| 19 | - | ||
| 20 | - /** | ||
| 21 | - * 设置数据源的变量 | ||
| 22 | - */ | ||
| 23 | - public static void setDataSourceType(String dsType) { | ||
| 24 | - log.info("切换到{}数据源", dsType); | ||
| 25 | - CONTEXT_HOLDER.set(dsType); | ||
| 26 | - } | ||
| 27 | - | ||
| 28 | - /** | ||
| 29 | - * 获得数据源的变量 | ||
| 30 | - */ | ||
| 31 | - public static String getDataSourceType() { | ||
| 32 | - return CONTEXT_HOLDER.get(); | ||
| 33 | - } | ||
| 34 | - | ||
| 35 | - /** | ||
| 36 | - * 清空数据源变量 | ||
| 37 | - */ | ||
| 38 | - public static void clearDataSourceType() { | ||
| 39 | - CONTEXT_HOLDER.remove(); | ||
| 40 | - } | ||
| 41 | -} | 1 | +package com.ruoyi.framework.datasource; |
| 2 | + | ||
| 3 | +import org.slf4j.Logger; | ||
| 4 | +import org.slf4j.LoggerFactory; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 数据源切换处理 | ||
| 8 | + * | ||
| 9 | + * @author ruoyi | ||
| 10 | + */ | ||
| 11 | +public class DynamicDataSourceContextHolder { | ||
| 12 | + public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class); | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本, | ||
| 16 | + * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 | ||
| 17 | + */ | ||
| 18 | + private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>(); | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 设置数据源的变量 | ||
| 22 | + */ | ||
| 23 | + public static void setDataSourceType(String dsType) { | ||
| 24 | + log.info("切换到{}数据源", dsType); | ||
| 25 | + CONTEXT_HOLDER.set(dsType); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 获得数据源的变量 | ||
| 30 | + */ | ||
| 31 | + public static String getDataSourceType() { | ||
| 32 | + return CONTEXT_HOLDER.get(); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * 清空数据源变量 | ||
| 37 | + */ | ||
| 38 | + public static void clearDataSourceType() { | ||
| 39 | + CONTEXT_HOLDER.remove(); | ||
| 40 | + } | ||
| 41 | +} |
ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/config/DruidConfig.java
| 1 | -package com.ruoyi.framework.config; | ||
| 2 | - | ||
| 3 | -import java.io.IOException; | ||
| 4 | -import java.util.HashMap; | ||
| 5 | -import java.util.Map; | ||
| 6 | -import javax.servlet.Filter; | ||
| 7 | -import javax.servlet.FilterChain; | ||
| 8 | -import javax.servlet.ServletException; | ||
| 9 | -import javax.servlet.ServletRequest; | ||
| 10 | -import javax.servlet.ServletResponse; | ||
| 11 | -import javax.sql.DataSource; | ||
| 12 | - | ||
| 13 | -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
| 14 | -import org.springframework.boot.context.properties.ConfigurationProperties; | ||
| 15 | -import org.springframework.boot.web.servlet.FilterRegistrationBean; | ||
| 16 | -import org.springframework.context.annotation.Bean; | ||
| 17 | -import org.springframework.context.annotation.Configuration; | ||
| 18 | -import org.springframework.context.annotation.Primary; | ||
| 19 | -import com.alibaba.druid.pool.DruidDataSource; | ||
| 20 | -import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; | ||
| 21 | -import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; | ||
| 22 | -import com.alibaba.druid.util.Utils; | ||
| 23 | -import com.ruoyi.common.enums.DataSourceType; | ||
| 24 | -import com.ruoyi.common.utils.spring.SpringUtils; | ||
| 25 | -import com.ruoyi.framework.config.properties.DruidProperties; | ||
| 26 | -import com.ruoyi.framework.datasource.DynamicDataSource; | ||
| 27 | - | ||
| 28 | -/** | ||
| 29 | - * druid 配置多数据源 | ||
| 30 | - * | ||
| 31 | - * @author ruoyi | ||
| 32 | - */ | ||
| 33 | -@Configuration | ||
| 34 | -public class DruidConfig { | ||
| 35 | - @Bean | ||
| 36 | - @ConfigurationProperties("spring.datasource.druid.master") | ||
| 37 | - public DataSource masterDataSource(DruidProperties druidProperties) { | ||
| 38 | - DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); | ||
| 39 | - return druidProperties.dataSource(dataSource); | ||
| 40 | - } | ||
| 41 | - | ||
| 42 | - @Bean | ||
| 43 | - @ConfigurationProperties("spring.datasource.druid.slave") | ||
| 44 | - @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") | ||
| 45 | - public DataSource slaveDataSource(DruidProperties druidProperties) { | ||
| 46 | - DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); | ||
| 47 | - return druidProperties.dataSource(dataSource); | ||
| 48 | - } | ||
| 49 | - | ||
| 50 | - @Bean(name = "dynamicDataSource") | ||
| 51 | - @Primary | ||
| 52 | - public DynamicDataSource dataSource(DataSource masterDataSource) { | ||
| 53 | - Map<Object, Object> targetDataSources = new HashMap<>(); | ||
| 54 | - targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource); | ||
| 55 | - setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource"); | ||
| 56 | - return new DynamicDataSource(masterDataSource, targetDataSources); | ||
| 57 | - } | ||
| 58 | - | ||
| 59 | - /** | ||
| 60 | - * 设置数据源 | ||
| 61 | - * | ||
| 62 | - * @param targetDataSources 备选数据源集合 | ||
| 63 | - * @param sourceName 数据源名称 | ||
| 64 | - * @param beanName bean名称 | ||
| 65 | - */ | ||
| 66 | - public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName) { | ||
| 67 | - try { | ||
| 68 | - DataSource dataSource = SpringUtils.getBean(beanName); | ||
| 69 | - targetDataSources.put(sourceName, dataSource); | ||
| 70 | - } catch (Exception e) { | ||
| 71 | - } | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - /** | ||
| 75 | - * 去除监控页面底部的广告 | ||
| 76 | - */ | ||
| 77 | - @SuppressWarnings({"rawtypes", "unchecked"}) | ||
| 78 | - @Bean | ||
| 79 | - @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true") | ||
| 80 | - public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) { | ||
| 81 | - // 获取web监控页面的参数 | ||
| 82 | - DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); | ||
| 83 | - // 提取common.js的配置路径 | ||
| 84 | - String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; | ||
| 85 | - String commonJsPattern = pattern.replaceAll("\\*", "js/common.js"); | ||
| 86 | - final String filePath = "support/http/resources/js/common.js"; | ||
| 87 | - // 创建filter进行过滤 | ||
| 88 | - Filter filter = new Filter() { | ||
| 89 | - @Override | ||
| 90 | - public void init(javax.servlet.FilterConfig filterConfig) throws ServletException { | ||
| 91 | - } | ||
| 92 | - | ||
| 93 | - @Override | ||
| 94 | - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | ||
| 95 | - throws IOException, ServletException { | ||
| 96 | - chain.doFilter(request, response); | ||
| 97 | - // 重置缓冲区,响应头不会被重置 | ||
| 98 | - response.resetBuffer(); | ||
| 99 | - // 获取common.js | ||
| 100 | - String text = Utils.readFromResource(filePath); | ||
| 101 | - // 正则替换banner, 除去底部的广告信息 | ||
| 102 | - text = text.replaceAll("<a.*?banner\"></a><br/>", ""); | ||
| 103 | - text = text.replaceAll("powered.*?shrek.wang</a>", ""); | ||
| 104 | - response.getWriter().write(text); | ||
| 105 | - } | ||
| 106 | - | ||
| 107 | - @Override | ||
| 108 | - public void destroy() { | ||
| 109 | - } | ||
| 110 | - }; | ||
| 111 | - FilterRegistrationBean registrationBean = new FilterRegistrationBean(); | ||
| 112 | - registrationBean.setFilter(filter); | ||
| 113 | - registrationBean.addUrlPatterns(commonJsPattern); | ||
| 114 | - return registrationBean; | ||
| 115 | - } | ||
| 116 | -} | 1 | +package com.ruoyi.framework.config; |
| 2 | + | ||
| 3 | +import java.io.IOException; | ||
| 4 | +import java.util.HashMap; | ||
| 5 | +import java.util.Map; | ||
| 6 | +import javax.servlet.Filter; | ||
| 7 | +import javax.servlet.FilterChain; | ||
| 8 | +import javax.servlet.ServletException; | ||
| 9 | +import javax.servlet.ServletRequest; | ||
| 10 | +import javax.servlet.ServletResponse; | ||
| 11 | +import javax.sql.DataSource; | ||
| 12 | + | ||
| 13 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
| 14 | +import org.springframework.boot.context.properties.ConfigurationProperties; | ||
| 15 | +import org.springframework.boot.web.servlet.FilterRegistrationBean; | ||
| 16 | +import org.springframework.context.annotation.Bean; | ||
| 17 | +import org.springframework.context.annotation.Configuration; | ||
| 18 | +import org.springframework.context.annotation.Primary; | ||
| 19 | +import com.alibaba.druid.pool.DruidDataSource; | ||
| 20 | +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; | ||
| 21 | +import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; | ||
| 22 | +import com.alibaba.druid.util.Utils; | ||
| 23 | +import com.ruoyi.common.enums.DataSourceType; | ||
| 24 | +import com.ruoyi.common.utils.spring.SpringUtils; | ||
| 25 | +import com.ruoyi.framework.config.properties.DruidProperties; | ||
| 26 | +import com.ruoyi.framework.datasource.DynamicDataSource; | ||
| 27 | + | ||
| 28 | +/** | ||
| 29 | + * druid 配置多数据源 | ||
| 30 | + * | ||
| 31 | + * @author ruoyi | ||
| 32 | + */ | ||
| 33 | +@Configuration | ||
| 34 | +public class DruidConfig { | ||
| 35 | + @Bean | ||
| 36 | + @ConfigurationProperties("spring.datasource.druid.master") | ||
| 37 | + public DataSource masterDataSource(DruidProperties druidProperties) { | ||
| 38 | + DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); | ||
| 39 | + return druidProperties.dataSource(dataSource); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + @Bean | ||
| 43 | + @ConfigurationProperties("spring.datasource.druid.slave") | ||
| 44 | + @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") | ||
| 45 | + public DataSource slaveDataSource(DruidProperties druidProperties) { | ||
| 46 | + DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); | ||
| 47 | + return druidProperties.dataSource(dataSource); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + @Bean(name = "dynamicDataSource") | ||
| 51 | + @Primary | ||
| 52 | + public DynamicDataSource dataSource(DataSource masterDataSource) { | ||
| 53 | + Map<Object, Object> targetDataSources = new HashMap<>(); | ||
| 54 | + targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource); | ||
| 55 | + setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource"); | ||
| 56 | + return new DynamicDataSource(masterDataSource, targetDataSources); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * 设置数据源 | ||
| 61 | + * | ||
| 62 | + * @param targetDataSources 备选数据源集合 | ||
| 63 | + * @param sourceName 数据源名称 | ||
| 64 | + * @param beanName bean名称 | ||
| 65 | + */ | ||
| 66 | + public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName) { | ||
| 67 | + try { | ||
| 68 | + DataSource dataSource = SpringUtils.getBean(beanName); | ||
| 69 | + targetDataSources.put(sourceName, dataSource); | ||
| 70 | + } catch (Exception e) { | ||
| 71 | + } | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + /** | ||
| 75 | + * 去除监控页面底部的广告 | ||
| 76 | + */ | ||
| 77 | + @SuppressWarnings({"rawtypes", "unchecked"}) | ||
| 78 | + @Bean | ||
| 79 | + @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true") | ||
| 80 | + public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) { | ||
| 81 | + // 获取web监控页面的参数 | ||
| 82 | + DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); | ||
| 83 | + // 提取common.js的配置路径 | ||
| 84 | + String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; | ||
| 85 | + String commonJsPattern = pattern.replaceAll("\\*", "js/common.js"); | ||
| 86 | + final String filePath = "support/http/resources/js/common.js"; | ||
| 87 | + // 创建filter进行过滤 | ||
| 88 | + Filter filter = new Filter() { | ||
| 89 | + @Override | ||
| 90 | + public void init(javax.servlet.FilterConfig filterConfig) throws ServletException { | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + @Override | ||
| 94 | + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | ||
| 95 | + throws IOException, ServletException { | ||
| 96 | + chain.doFilter(request, response); | ||
| 97 | + // 重置缓冲区,响应头不会被重置 | ||
| 98 | + response.resetBuffer(); | ||
| 99 | + // 获取common.js | ||
| 100 | + String text = Utils.readFromResource(filePath); | ||
| 101 | + // 正则替换banner, 除去底部的广告信息 | ||
| 102 | + text = text.replaceAll("<a.*?banner\"></a><br/>", ""); | ||
| 103 | + text = text.replaceAll("powered.*?shrek.wang</a>", ""); | ||
| 104 | + response.getWriter().write(text); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + @Override | ||
| 108 | + public void destroy() { | ||
| 109 | + } | ||
| 110 | + }; | ||
| 111 | + FilterRegistrationBean registrationBean = new FilterRegistrationBean(); | ||
| 112 | + registrationBean.setFilter(filter); | ||
| 113 | + registrationBean.addUrlPatterns(commonJsPattern); | ||
| 114 | + return registrationBean; | ||
| 115 | + } | ||
| 116 | +} |
ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/config/FilterConfig.java
| 1 | -package com.ruoyi.framework.config; | ||
| 2 | - | ||
| 3 | -import java.util.HashMap; | ||
| 4 | -import java.util.Map; | ||
| 5 | -import javax.servlet.DispatcherType; | ||
| 6 | - | ||
| 7 | -import org.springframework.beans.factory.annotation.Value; | ||
| 8 | -import org.springframework.boot.web.servlet.FilterRegistrationBean; | ||
| 9 | -import org.springframework.context.annotation.Bean; | ||
| 10 | -import org.springframework.context.annotation.Configuration; | ||
| 11 | -import com.ruoyi.common.filter.RepeatableFilter; | ||
| 12 | -import com.ruoyi.common.filter.XssFilter; | ||
| 13 | -import com.ruoyi.common.utils.StringUtils; | ||
| 14 | - | ||
| 15 | -/** | ||
| 16 | - * Filter配置 | ||
| 17 | - * | ||
| 18 | - * @author ruoyi | ||
| 19 | - */ | ||
| 20 | -@Configuration | ||
| 21 | -public class FilterConfig { | ||
| 22 | - @Value("${xss.enabled}") | ||
| 23 | - private String enabled; | ||
| 24 | - | ||
| 25 | - @Value("${xss.excludes}") | ||
| 26 | - private String excludes; | ||
| 27 | - | ||
| 28 | - @Value("${xss.urlPatterns}") | ||
| 29 | - private String urlPatterns; | ||
| 30 | - | ||
| 31 | - @SuppressWarnings({"rawtypes", "unchecked"}) | ||
| 32 | - @Bean | ||
| 33 | - public FilterRegistrationBean xssFilterRegistration() { | ||
| 34 | - FilterRegistrationBean registration = new FilterRegistrationBean(); | ||
| 35 | - registration.setDispatcherTypes(DispatcherType.REQUEST); | ||
| 36 | - registration.setFilter(new XssFilter()); | ||
| 37 | - registration.addUrlPatterns(StringUtils.split(urlPatterns, ",")); | ||
| 38 | - registration.setName("xssFilter"); | ||
| 39 | - registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); | ||
| 40 | - Map<String, String> initParameters = new HashMap<String, String>(); | ||
| 41 | - initParameters.put("excludes", excludes); | ||
| 42 | - initParameters.put("enabled", enabled); | ||
| 43 | - registration.setInitParameters(initParameters); | ||
| 44 | - return registration; | ||
| 45 | - } | ||
| 46 | - | ||
| 47 | - @SuppressWarnings({"rawtypes", "unchecked"}) | ||
| 48 | - @Bean | ||
| 49 | - public FilterRegistrationBean someFilterRegistration() { | ||
| 50 | - FilterRegistrationBean registration = new FilterRegistrationBean(); | ||
| 51 | - registration.setFilter(new RepeatableFilter()); | ||
| 52 | - registration.addUrlPatterns("/*"); | ||
| 53 | - registration.setName("repeatableFilter"); | ||
| 54 | - registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE); | ||
| 55 | - return registration; | ||
| 56 | - } | ||
| 57 | - | ||
| 58 | -} | 1 | +package com.ruoyi.framework.config; |
| 2 | + | ||
| 3 | +import java.util.HashMap; | ||
| 4 | +import java.util.Map; | ||
| 5 | +import javax.servlet.DispatcherType; | ||
| 6 | + | ||
| 7 | +import org.springframework.beans.factory.annotation.Value; | ||
| 8 | +import org.springframework.boot.web.servlet.FilterRegistrationBean; | ||
| 9 | +import org.springframework.context.annotation.Bean; | ||
| 10 | +import org.springframework.context.annotation.Configuration; | ||
| 11 | +import com.ruoyi.common.filter.RepeatableFilter; | ||
| 12 | +import com.ruoyi.common.filter.XssFilter; | ||
| 13 | +import com.ruoyi.common.utils.StringUtils; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * Filter配置 | ||
| 17 | + * | ||
| 18 | + * @author ruoyi | ||
| 19 | + */ | ||
| 20 | +@Configuration | ||
| 21 | +public class FilterConfig { | ||
| 22 | + @Value("${xss.enabled}") | ||
| 23 | + private String enabled; | ||
| 24 | + | ||
| 25 | + @Value("${xss.excludes}") | ||
| 26 | + private String excludes; | ||
| 27 | + | ||
| 28 | + @Value("${xss.urlPatterns}") | ||
| 29 | + private String urlPatterns; | ||
| 30 | + | ||
| 31 | + @SuppressWarnings({"rawtypes", "unchecked"}) | ||
| 32 | + @Bean | ||
| 33 | + public FilterRegistrationBean xssFilterRegistration() { | ||
| 34 | + FilterRegistrationBean registration = new FilterRegistrationBean(); | ||
| 35 | + registration.setDispatcherTypes(DispatcherType.REQUEST); | ||
| 36 | + registration.setFilter(new XssFilter()); | ||
| 37 | + registration.addUrlPatterns(StringUtils.split(urlPatterns, ",")); | ||
| 38 | + registration.setName("xssFilter"); | ||
| 39 | + registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); | ||
| 40 | + Map<String, String> initParameters = new HashMap<String, String>(); | ||
| 41 | + initParameters.put("excludes", excludes); | ||
| 42 | + initParameters.put("enabled", enabled); | ||
| 43 | + registration.setInitParameters(initParameters); | ||
| 44 | + return registration; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + @SuppressWarnings({"rawtypes", "unchecked"}) | ||
| 48 | + @Bean | ||
| 49 | + public FilterRegistrationBean someFilterRegistration() { | ||
| 50 | + FilterRegistrationBean registration = new FilterRegistrationBean(); | ||
| 51 | + registration.setFilter(new RepeatableFilter()); | ||
| 52 | + registration.addUrlPatterns("/*"); | ||
| 53 | + registration.setName("repeatableFilter"); | ||
| 54 | + registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE); | ||
| 55 | + return registration; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | +} |
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/config/ResourcesConfig.java
| 1 | -package com.ruoyi.framework.config; | ||
| 2 | - | ||
| 3 | -import org.springframework.beans.factory.annotation.Autowired; | ||
| 4 | -import org.springframework.context.annotation.Bean; | ||
| 5 | -import org.springframework.context.annotation.Configuration; | ||
| 6 | -import org.springframework.web.cors.CorsConfiguration; | ||
| 7 | -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; | ||
| 8 | -import org.springframework.web.filter.CorsFilter; | ||
| 9 | -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; | ||
| 10 | -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; | ||
| 11 | -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||
| 12 | -import com.ruoyi.common.config.RuoYiConfig; | ||
| 13 | -import com.ruoyi.common.constant.Constants; | ||
| 14 | -import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; | ||
| 15 | - | ||
| 16 | -/** | ||
| 17 | - * 通用配置 | ||
| 18 | - * | ||
| 19 | - * @author ruoyi | ||
| 20 | - */ | ||
| 21 | -@Configuration | ||
| 22 | -public class ResourcesConfig implements WebMvcConfigurer { | ||
| 23 | - @Autowired | ||
| 24 | - private RepeatSubmitInterceptor repeatSubmitInterceptor; | ||
| 25 | - | ||
| 26 | - @Override | ||
| 27 | - public void addResourceHandlers(ResourceHandlerRegistry registry) { | ||
| 28 | - /** 本地文件上传路径 */ | ||
| 29 | - registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/"); | ||
| 30 | - | ||
| 31 | - /** swagger配置 */ | ||
| 32 | - registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); | ||
| 33 | - registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); | ||
| 34 | - } | ||
| 35 | - | ||
| 36 | - /** | ||
| 37 | - * 自定义拦截规则 | ||
| 38 | - */ | ||
| 39 | - @Override | ||
| 40 | - public void addInterceptors(InterceptorRegistry registry) { | ||
| 41 | - registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**"); | ||
| 42 | - } | ||
| 43 | - | ||
| 44 | -} | 1 | +package com.ruoyi.framework.config; |
| 2 | + | ||
| 3 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 4 | +import org.springframework.context.annotation.Bean; | ||
| 5 | +import org.springframework.context.annotation.Configuration; | ||
| 6 | +import org.springframework.web.cors.CorsConfiguration; | ||
| 7 | +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; | ||
| 8 | +import org.springframework.web.filter.CorsFilter; | ||
| 9 | +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; | ||
| 10 | +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; | ||
| 11 | +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||
| 12 | +import com.ruoyi.common.config.RuoYiConfig; | ||
| 13 | +import com.ruoyi.common.constant.Constants; | ||
| 14 | +import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * 通用配置 | ||
| 18 | + * | ||
| 19 | + * @author ruoyi | ||
| 20 | + */ | ||
| 21 | +@Configuration | ||
| 22 | +public class ResourcesConfig implements WebMvcConfigurer { | ||
| 23 | + @Autowired | ||
| 24 | + private RepeatSubmitInterceptor repeatSubmitInterceptor; | ||
| 25 | + | ||
| 26 | + @Override | ||
| 27 | + public void addResourceHandlers(ResourceHandlerRegistry registry) { | ||
| 28 | + /** 本地文件上传路径 */ | ||
| 29 | + registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/"); | ||
| 30 | + | ||
| 31 | + /** swagger配置 */ | ||
| 32 | + registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); | ||
| 33 | + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + /** | ||
| 37 | + * 自定义拦截规则 | ||
| 38 | + */ | ||
| 39 | + @Override | ||
| 40 | + public void addInterceptors(InterceptorRegistry registry) { | ||
| 41 | + registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**"); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | +} |
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ServerConfig.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/config/ServerConfig.java
| 1 | -package com.ruoyi.framework.config; | ||
| 2 | - | ||
| 3 | -import javax.servlet.http.HttpServletRequest; | ||
| 4 | - | ||
| 5 | -import org.springframework.stereotype.Component; | ||
| 6 | -import com.ruoyi.common.utils.ServletUtils; | ||
| 7 | - | ||
| 8 | -/** | ||
| 9 | - * 服务相关配置 | ||
| 10 | - * | ||
| 11 | - * @author ruoyi | ||
| 12 | - */ | ||
| 13 | -@Component | ||
| 14 | -public class ServerConfig { | ||
| 15 | - /** | ||
| 16 | - * 获取完整的请求路径,包括:域名,端口,上下文访问路径 | ||
| 17 | - * | ||
| 18 | - * @return 服务地址 | ||
| 19 | - */ | ||
| 20 | - public String getUrl() { | ||
| 21 | - HttpServletRequest request = ServletUtils.getRequest(); | ||
| 22 | - return getDomain(request); | ||
| 23 | - } | ||
| 24 | - | ||
| 25 | - public static String getDomain(HttpServletRequest request) { | ||
| 26 | - StringBuffer url = request.getRequestURL(); | ||
| 27 | - String contextPath = request.getServletContext().getContextPath(); | ||
| 28 | - return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString(); | ||
| 29 | - } | ||
| 30 | -} | 1 | +package com.ruoyi.framework.config; |
| 2 | + | ||
| 3 | +import javax.servlet.http.HttpServletRequest; | ||
| 4 | + | ||
| 5 | +import org.springframework.stereotype.Component; | ||
| 6 | +import com.ruoyi.common.utils.ServletUtils; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 服务相关配置 | ||
| 10 | + * | ||
| 11 | + * @author ruoyi | ||
| 12 | + */ | ||
| 13 | +@Component | ||
| 14 | +public class ServerConfig { | ||
| 15 | + /** | ||
| 16 | + * 获取完整的请求路径,包括:域名,端口,上下文访问路径 | ||
| 17 | + * | ||
| 18 | + * @return 服务地址 | ||
| 19 | + */ | ||
| 20 | + public String getUrl() { | ||
| 21 | + HttpServletRequest request = ServletUtils.getRequest(); | ||
| 22 | + return getDomain(request); | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + public static String getDomain(HttpServletRequest request) { | ||
| 26 | + StringBuffer url = request.getRequestURL(); | ||
| 27 | + String contextPath = request.getServletContext().getContextPath(); | ||
| 28 | + return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString(); | ||
| 29 | + } | ||
| 30 | +} |
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/config/ThreadPoolConfig.java
| 1 | -package com.ruoyi.framework.config; | ||
| 2 | - | ||
| 3 | -import java.util.concurrent.ScheduledExecutorService; | ||
| 4 | -import java.util.concurrent.ScheduledThreadPoolExecutor; | ||
| 5 | -import java.util.concurrent.ThreadPoolExecutor; | ||
| 6 | - | ||
| 7 | -import org.apache.commons.lang3.concurrent.BasicThreadFactory; | ||
| 8 | -import org.springframework.context.annotation.Bean; | ||
| 9 | -import org.springframework.context.annotation.Configuration; | ||
| 10 | -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | ||
| 11 | -import com.ruoyi.common.utils.Threads; | ||
| 12 | - | ||
| 13 | -/** | ||
| 14 | - * 线程池配置 | ||
| 15 | - * | ||
| 16 | - * @author ruoyi | ||
| 17 | - **/ | ||
| 18 | -@Configuration | ||
| 19 | -public class ThreadPoolConfig { | ||
| 20 | - // 核心线程池大小 | ||
| 21 | - private int corePoolSize = 50; | ||
| 22 | - | ||
| 23 | - // 最大可创建的线程数 | ||
| 24 | - private int maxPoolSize = 200; | ||
| 25 | - | ||
| 26 | - // 队列最大长度 | ||
| 27 | - private int queueCapacity = 1000; | ||
| 28 | - | ||
| 29 | - // 线程池维护线程所允许的空闲时间 | ||
| 30 | - private int keepAliveSeconds = 300; | ||
| 31 | - | ||
| 32 | - @Bean(name = "threadPoolTaskExecutor") | ||
| 33 | - public ThreadPoolTaskExecutor threadPoolTaskExecutor() { | ||
| 34 | - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); | ||
| 35 | - executor.setMaxPoolSize(maxPoolSize); | ||
| 36 | - executor.setCorePoolSize(corePoolSize); | ||
| 37 | - executor.setQueueCapacity(queueCapacity); | ||
| 38 | - executor.setKeepAliveSeconds(keepAliveSeconds); | ||
| 39 | - // 线程池对拒绝任务(无线程可用)的处理策略 | ||
| 40 | - executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); | ||
| 41 | - return executor; | ||
| 42 | - } | ||
| 43 | - | ||
| 44 | - /** | ||
| 45 | - * 执行周期性或定时任务 | ||
| 46 | - */ | ||
| 47 | - @Bean(name = "scheduledExecutorService") | ||
| 48 | - protected ScheduledExecutorService scheduledExecutorService() { | ||
| 49 | - return new ScheduledThreadPoolExecutor(corePoolSize, | ||
| 50 | - new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) { | ||
| 51 | - @Override | ||
| 52 | - protected void afterExecute(Runnable r, Throwable t) { | ||
| 53 | - super.afterExecute(r, t); | ||
| 54 | - Threads.printException(r, t); | ||
| 55 | - } | ||
| 56 | - }; | ||
| 57 | - } | ||
| 58 | -} | 1 | +package com.ruoyi.framework.config; |
| 2 | + | ||
| 3 | +import java.util.concurrent.ScheduledExecutorService; | ||
| 4 | +import java.util.concurrent.ScheduledThreadPoolExecutor; | ||
| 5 | +import java.util.concurrent.ThreadPoolExecutor; | ||
| 6 | + | ||
| 7 | +import org.apache.commons.lang3.concurrent.BasicThreadFactory; | ||
| 8 | +import org.springframework.context.annotation.Bean; | ||
| 9 | +import org.springframework.context.annotation.Configuration; | ||
| 10 | +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | ||
| 11 | +import com.ruoyi.common.utils.Threads; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * 线程池配置 | ||
| 15 | + * | ||
| 16 | + * @author ruoyi | ||
| 17 | + **/ | ||
| 18 | +@Configuration | ||
| 19 | +public class ThreadPoolConfig { | ||
| 20 | + // 核心线程池大小 | ||
| 21 | + private int corePoolSize = 50; | ||
| 22 | + | ||
| 23 | + // 最大可创建的线程数 | ||
| 24 | + private int maxPoolSize = 200; | ||
| 25 | + | ||
| 26 | + // 队列最大长度 | ||
| 27 | + private int queueCapacity = 1000; | ||
| 28 | + | ||
| 29 | + // 线程池维护线程所允许的空闲时间 | ||
| 30 | + private int keepAliveSeconds = 300; | ||
| 31 | + | ||
| 32 | + @Bean(name = "threadPoolTaskExecutor") | ||
| 33 | + public ThreadPoolTaskExecutor threadPoolTaskExecutor() { | ||
| 34 | + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); | ||
| 35 | + executor.setMaxPoolSize(maxPoolSize); | ||
| 36 | + executor.setCorePoolSize(corePoolSize); | ||
| 37 | + executor.setQueueCapacity(queueCapacity); | ||
| 38 | + executor.setKeepAliveSeconds(keepAliveSeconds); | ||
| 39 | + // 线程池对拒绝任务(无线程可用)的处理策略 | ||
| 40 | + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); | ||
| 41 | + return executor; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * 执行周期性或定时任务 | ||
| 46 | + */ | ||
| 47 | + @Bean(name = "scheduledExecutorService") | ||
| 48 | + protected ScheduledExecutorService scheduledExecutorService() { | ||
| 49 | + return new ScheduledThreadPoolExecutor(corePoolSize, | ||
| 50 | + new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) { | ||
| 51 | + @Override | ||
| 52 | + protected void afterExecute(Runnable r, Throwable t) { | ||
| 53 | + super.afterExecute(r, t); | ||
| 54 | + Threads.printException(r, t); | ||
| 55 | + } | ||
| 56 | + }; | ||
| 57 | + } | ||
| 58 | +} |
ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/config/properties/DruidProperties.java
| 1 | -package com.ruoyi.framework.config.properties; | ||
| 2 | - | ||
| 3 | -import org.springframework.beans.factory.annotation.Value; | ||
| 4 | -import org.springframework.context.annotation.Configuration; | ||
| 5 | -import com.alibaba.druid.pool.DruidDataSource; | ||
| 6 | - | ||
| 7 | -/** | ||
| 8 | - * druid 配置属性 | ||
| 9 | - * | ||
| 10 | - * @author ruoyi | ||
| 11 | - */ | ||
| 12 | -@Configuration | ||
| 13 | -public class DruidProperties { | ||
| 14 | - @Value("${spring.datasource.druid.initialSize}") | ||
| 15 | - private int initialSize; | ||
| 16 | - | ||
| 17 | - @Value("${spring.datasource.druid.minIdle}") | ||
| 18 | - private int minIdle; | ||
| 19 | - | ||
| 20 | - @Value("${spring.datasource.druid.maxActive}") | ||
| 21 | - private int maxActive; | ||
| 22 | - | ||
| 23 | - @Value("${spring.datasource.druid.maxWait}") | ||
| 24 | - private int maxWait; | ||
| 25 | - | ||
| 26 | - @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}") | ||
| 27 | - private int timeBetweenEvictionRunsMillis; | ||
| 28 | - | ||
| 29 | - @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}") | ||
| 30 | - private int minEvictableIdleTimeMillis; | ||
| 31 | - | ||
| 32 | - @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}") | ||
| 33 | - private int maxEvictableIdleTimeMillis; | ||
| 34 | - | ||
| 35 | - @Value("${spring.datasource.druid.validationQuery}") | ||
| 36 | - private String validationQuery; | ||
| 37 | - | ||
| 38 | - @Value("${spring.datasource.druid.testWhileIdle}") | ||
| 39 | - private boolean testWhileIdle; | ||
| 40 | - | ||
| 41 | - @Value("${spring.datasource.druid.testOnBorrow}") | ||
| 42 | - private boolean testOnBorrow; | ||
| 43 | - | ||
| 44 | - @Value("${spring.datasource.druid.testOnReturn}") | ||
| 45 | - private boolean testOnReturn; | ||
| 46 | - | ||
| 47 | - public DruidDataSource dataSource(DruidDataSource datasource) { | ||
| 48 | - /** 配置初始化大小、最小、最大 */ | ||
| 49 | - datasource.setInitialSize(initialSize); | ||
| 50 | - datasource.setMaxActive(maxActive); | ||
| 51 | - datasource.setMinIdle(minIdle); | ||
| 52 | - | ||
| 53 | - /** 配置获取连接等待超时的时间 */ | ||
| 54 | - datasource.setMaxWait(maxWait); | ||
| 55 | - | ||
| 56 | - /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */ | ||
| 57 | - datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); | ||
| 58 | - | ||
| 59 | - /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */ | ||
| 60 | - datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); | ||
| 61 | - datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis); | ||
| 62 | - | ||
| 63 | - /** | ||
| 64 | - * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。 | ||
| 65 | - */ | ||
| 66 | - datasource.setValidationQuery(validationQuery); | ||
| 67 | - /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */ | ||
| 68 | - datasource.setTestWhileIdle(testWhileIdle); | ||
| 69 | - /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ | ||
| 70 | - datasource.setTestOnBorrow(testOnBorrow); | ||
| 71 | - /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ | ||
| 72 | - datasource.setTestOnReturn(testOnReturn); | ||
| 73 | - return datasource; | ||
| 74 | - } | ||
| 75 | -} | 1 | +package com.ruoyi.framework.config.properties; |
| 2 | + | ||
| 3 | +import org.springframework.beans.factory.annotation.Value; | ||
| 4 | +import org.springframework.context.annotation.Configuration; | ||
| 5 | +import com.alibaba.druid.pool.DruidDataSource; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * druid 配置属性 | ||
| 9 | + * | ||
| 10 | + * @author ruoyi | ||
| 11 | + */ | ||
| 12 | +@Configuration | ||
| 13 | +public class DruidProperties { | ||
| 14 | + @Value("${spring.datasource.druid.initialSize}") | ||
| 15 | + private int initialSize; | ||
| 16 | + | ||
| 17 | + @Value("${spring.datasource.druid.minIdle}") | ||
| 18 | + private int minIdle; | ||
| 19 | + | ||
| 20 | + @Value("${spring.datasource.druid.maxActive}") | ||
| 21 | + private int maxActive; | ||
| 22 | + | ||
| 23 | + @Value("${spring.datasource.druid.maxWait}") | ||
| 24 | + private int maxWait; | ||
| 25 | + | ||
| 26 | + @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}") | ||
| 27 | + private int timeBetweenEvictionRunsMillis; | ||
| 28 | + | ||
| 29 | + @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}") | ||
| 30 | + private int minEvictableIdleTimeMillis; | ||
| 31 | + | ||
| 32 | + @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}") | ||
| 33 | + private int maxEvictableIdleTimeMillis; | ||
| 34 | + | ||
| 35 | + @Value("${spring.datasource.druid.validationQuery}") | ||
| 36 | + private String validationQuery; | ||
| 37 | + | ||
| 38 | + @Value("${spring.datasource.druid.testWhileIdle}") | ||
| 39 | + private boolean testWhileIdle; | ||
| 40 | + | ||
| 41 | + @Value("${spring.datasource.druid.testOnBorrow}") | ||
| 42 | + private boolean testOnBorrow; | ||
| 43 | + | ||
| 44 | + @Value("${spring.datasource.druid.testOnReturn}") | ||
| 45 | + private boolean testOnReturn; | ||
| 46 | + | ||
| 47 | + public DruidDataSource dataSource(DruidDataSource datasource) { | ||
| 48 | + /** 配置初始化大小、最小、最大 */ | ||
| 49 | + datasource.setInitialSize(initialSize); | ||
| 50 | + datasource.setMaxActive(maxActive); | ||
| 51 | + datasource.setMinIdle(minIdle); | ||
| 52 | + | ||
| 53 | + /** 配置获取连接等待超时的时间 */ | ||
| 54 | + datasource.setMaxWait(maxWait); | ||
| 55 | + | ||
| 56 | + /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */ | ||
| 57 | + datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); | ||
| 58 | + | ||
| 59 | + /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */ | ||
| 60 | + datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); | ||
| 61 | + datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis); | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。 | ||
| 65 | + */ | ||
| 66 | + datasource.setValidationQuery(validationQuery); | ||
| 67 | + /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */ | ||
| 68 | + datasource.setTestWhileIdle(testWhileIdle); | ||
| 69 | + /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ | ||
| 70 | + datasource.setTestOnBorrow(testOnBorrow); | ||
| 71 | + /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ | ||
| 72 | + datasource.setTestOnReturn(testOnReturn); | ||
| 73 | + return datasource; | ||
| 74 | + } | ||
| 75 | +} |
ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatSubmit.java
| 1 | -package com.ruoyi.common.annotation; | ||
| 2 | - | ||
| 3 | -import java.lang.annotation.Documented; | ||
| 4 | -import java.lang.annotation.ElementType; | ||
| 5 | -import java.lang.annotation.Inherited; | ||
| 6 | -import java.lang.annotation.Retention; | ||
| 7 | -import java.lang.annotation.RetentionPolicy; | ||
| 8 | -import java.lang.annotation.Target; | ||
| 9 | - | ||
| 10 | -/** | ||
| 11 | - * 自定义注解防止表单重复提交 | ||
| 12 | - * | ||
| 13 | - * @author ruoyi | ||
| 14 | - */ | ||
| 15 | -@Inherited | ||
| 16 | -@Target(ElementType.METHOD) | ||
| 17 | -@Retention(RetentionPolicy.RUNTIME) | ||
| 18 | -@Documented | ||
| 19 | -public @interface RepeatSubmit { | ||
| 20 | - | ||
| 21 | -} | 1 | +package com.ruoyi.common.annotation; |
| 2 | + | ||
| 3 | +import java.lang.annotation.Documented; | ||
| 4 | +import java.lang.annotation.ElementType; | ||
| 5 | +import java.lang.annotation.Inherited; | ||
| 6 | +import java.lang.annotation.Retention; | ||
| 7 | +import java.lang.annotation.RetentionPolicy; | ||
| 8 | +import java.lang.annotation.Target; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 自定义注解防止表单重复提交 | ||
| 12 | + * | ||
| 13 | + * @author ruoyi | ||
| 14 | + */ | ||
| 15 | +@Inherited | ||
| 16 | +@Target(ElementType.METHOD) | ||
| 17 | +@Retention(RetentionPolicy.RUNTIME) | ||
| 18 | +@Documented | ||
| 19 | +public @interface RepeatSubmit { | ||
| 20 | + | ||
| 21 | +} |
ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatSubmitInterceptor.java
| 1 | -package com.ruoyi.framework.interceptor; | ||
| 2 | - | ||
| 3 | -import java.lang.reflect.Method; | ||
| 4 | -import javax.servlet.http.HttpServletRequest; | ||
| 5 | -import javax.servlet.http.HttpServletResponse; | ||
| 6 | - | ||
| 7 | -import org.springframework.stereotype.Component; | ||
| 8 | -import org.springframework.web.method.HandlerMethod; | ||
| 9 | -import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; | ||
| 10 | -import com.alibaba.fastjson.JSONObject; | ||
| 11 | -import com.ruoyi.common.annotation.RepeatSubmit; | ||
| 12 | -import com.ruoyi.common.core.domain.AjaxResult; | ||
| 13 | -import com.ruoyi.common.utils.ServletUtils; | ||
| 14 | - | ||
| 15 | -/** | ||
| 16 | - * 防止重复提交拦截器 | ||
| 17 | - * | ||
| 18 | - * @author ruoyi | ||
| 19 | - */ | ||
| 20 | -@Component | ||
| 21 | -public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter { | ||
| 22 | - @Override | ||
| 23 | - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { | ||
| 24 | - if (handler instanceof HandlerMethod) { | ||
| 25 | - HandlerMethod handlerMethod = (HandlerMethod) handler; | ||
| 26 | - Method method = handlerMethod.getMethod(); | ||
| 27 | - RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); | ||
| 28 | - if (annotation != null) { | ||
| 29 | - if (this.isRepeatSubmit(request)) { | ||
| 30 | - AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试"); | ||
| 31 | - ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult)); | ||
| 32 | - return false; | ||
| 33 | - } | ||
| 34 | - } | ||
| 35 | - return true; | ||
| 36 | - } else { | ||
| 37 | - return super.preHandle(request, response, handler); | ||
| 38 | - } | ||
| 39 | - } | ||
| 40 | - | ||
| 41 | - /** | ||
| 42 | - * 验证是否重复提交由子类实现具体的防重复提交的规则 | ||
| 43 | - * | ||
| 44 | - * @param request | ||
| 45 | - * @return | ||
| 46 | - * @throws Exception | ||
| 47 | - */ | ||
| 48 | - public abstract boolean isRepeatSubmit(HttpServletRequest request); | ||
| 49 | -} | 1 | +package com.ruoyi.framework.interceptor; |
| 2 | + | ||
| 3 | +import java.lang.reflect.Method; | ||
| 4 | +import javax.servlet.http.HttpServletRequest; | ||
| 5 | +import javax.servlet.http.HttpServletResponse; | ||
| 6 | + | ||
| 7 | +import org.springframework.stereotype.Component; | ||
| 8 | +import org.springframework.web.method.HandlerMethod; | ||
| 9 | +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; | ||
| 10 | +import com.alibaba.fastjson.JSONObject; | ||
| 11 | +import com.ruoyi.common.annotation.RepeatSubmit; | ||
| 12 | +import com.ruoyi.common.core.domain.AjaxResult; | ||
| 13 | +import com.ruoyi.common.utils.ServletUtils; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * 防止重复提交拦截器 | ||
| 17 | + * | ||
| 18 | + * @author ruoyi | ||
| 19 | + */ | ||
| 20 | +@Component | ||
| 21 | +public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter { | ||
| 22 | + @Override | ||
| 23 | + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { | ||
| 24 | + if (handler instanceof HandlerMethod) { | ||
| 25 | + HandlerMethod handlerMethod = (HandlerMethod) handler; | ||
| 26 | + Method method = handlerMethod.getMethod(); | ||
| 27 | + RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); | ||
| 28 | + if (annotation != null) { | ||
| 29 | + if (this.isRepeatSubmit(request)) { | ||
| 30 | + AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试"); | ||
| 31 | + ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult)); | ||
| 32 | + return false; | ||
| 33 | + } | ||
| 34 | + } | ||
| 35 | + return true; | ||
| 36 | + } else { | ||
| 37 | + return super.preHandle(request, response, handler); | ||
| 38 | + } | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * 验证是否重复提交由子类实现具体的防重复提交的规则 | ||
| 43 | + * | ||
| 44 | + * @param request | ||
| 45 | + * @return | ||
| 46 | + * @throws Exception | ||
| 47 | + */ | ||
| 48 | + public abstract boolean isRepeatSubmit(HttpServletRequest request); | ||
| 49 | +} |
ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java renamed to ruoyi-common/src/main/java/com/ruoyi/common/filter/SameUrlDataInterceptor.java
| 1 | -package com.ruoyi.framework.interceptor.impl; | ||
| 2 | - | ||
| 3 | -import java.util.HashMap; | ||
| 4 | -import java.util.Map; | ||
| 5 | -import java.util.concurrent.TimeUnit; | ||
| 6 | -import javax.servlet.http.HttpServletRequest; | ||
| 7 | - | ||
| 8 | -import org.springframework.beans.factory.annotation.Autowired; | ||
| 9 | -import org.springframework.beans.factory.annotation.Value; | ||
| 10 | -import org.springframework.stereotype.Component; | ||
| 11 | -import com.alibaba.fastjson.JSONObject; | ||
| 12 | -import com.ruoyi.common.constant.Constants; | ||
| 13 | -import com.ruoyi.common.core.redis.RedisCache; | ||
| 14 | -import com.ruoyi.common.filter.RepeatedlyRequestWrapper; | ||
| 15 | -import com.ruoyi.common.utils.StringUtils; | ||
| 16 | -import com.ruoyi.common.utils.http.HttpHelper; | ||
| 17 | -import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; | ||
| 18 | - | ||
| 19 | -/** | ||
| 20 | - * 判断请求url和数据是否和上一次相同, | ||
| 21 | - * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。 | ||
| 22 | - * | ||
| 23 | - * @author ruoyi | ||
| 24 | - */ | ||
| 25 | -@Component | ||
| 26 | -public class SameUrlDataInterceptor extends RepeatSubmitInterceptor { | ||
| 27 | - public final String REPEAT_PARAMS = "repeatParams"; | ||
| 28 | - | ||
| 29 | - public final String REPEAT_TIME = "repeatTime"; | ||
| 30 | - | ||
| 31 | - // 令牌自定义标识 | ||
| 32 | - @Value("${token.header}") | ||
| 33 | - private String header; | ||
| 34 | - | ||
| 35 | - @Autowired | ||
| 36 | - private RedisCache redisCache; | ||
| 37 | - | ||
| 38 | - /** | ||
| 39 | - * 间隔时间,单位:秒 默认10秒 | ||
| 40 | - * <p> | ||
| 41 | - * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据 | ||
| 42 | - */ | ||
| 43 | - private int intervalTime = 10; | ||
| 44 | - | ||
| 45 | - public void setIntervalTime(int intervalTime) { | ||
| 46 | - this.intervalTime = intervalTime; | ||
| 47 | - } | ||
| 48 | - | ||
| 49 | - @SuppressWarnings("unchecked") | ||
| 50 | - @Override | ||
| 51 | - public boolean isRepeatSubmit(HttpServletRequest request) { | ||
| 52 | - String nowParams = ""; | ||
| 53 | - if (request instanceof RepeatedlyRequestWrapper) { | ||
| 54 | - RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request; | ||
| 55 | - nowParams = HttpHelper.getBodyString(repeatedlyRequest); | ||
| 56 | - } | ||
| 57 | - | ||
| 58 | - // body参数为空,获取Parameter的数据 | ||
| 59 | - if (StringUtils.isEmpty(nowParams)) { | ||
| 60 | - nowParams = JSONObject.toJSONString(request.getParameterMap()); | ||
| 61 | - } | ||
| 62 | - Map<String, Object> nowDataMap = new HashMap<String, Object>(); | ||
| 63 | - nowDataMap.put(REPEAT_PARAMS, nowParams); | ||
| 64 | - nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); | ||
| 65 | - | ||
| 66 | - // 请求地址(作为存放cache的key值) | ||
| 67 | - String url = request.getRequestURI(); | ||
| 68 | - | ||
| 69 | - // 唯一值(没有消息头则使用请求地址) | ||
| 70 | - String submitKey = request.getHeader(header); | ||
| 71 | - if (StringUtils.isEmpty(submitKey)) { | ||
| 72 | - submitKey = url; | ||
| 73 | - } | ||
| 74 | - | ||
| 75 | - // 唯一标识(指定key + 消息头) | ||
| 76 | - String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey; | ||
| 77 | - | ||
| 78 | - Object sessionObj = redisCache.getCacheObject(cache_repeat_key); | ||
| 79 | - if (sessionObj != null) { | ||
| 80 | - Map<String, Object> sessionMap = (Map<String, Object>) sessionObj; | ||
| 81 | - if (sessionMap.containsKey(url)) { | ||
| 82 | - Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url); | ||
| 83 | - if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap)) { | ||
| 84 | - return true; | ||
| 85 | - } | ||
| 86 | - } | ||
| 87 | - } | ||
| 88 | - Map<String, Object> cacheMap = new HashMap<String, Object>(); | ||
| 89 | - cacheMap.put(url, nowDataMap); | ||
| 90 | - redisCache.setCacheObject(cache_repeat_key, cacheMap, intervalTime, TimeUnit.SECONDS); | ||
| 91 | - return false; | ||
| 92 | - } | ||
| 93 | - | ||
| 94 | - /** | ||
| 95 | - * 判断参数是否相同 | ||
| 96 | - */ | ||
| 97 | - private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap) { | ||
| 98 | - String nowParams = (String) nowMap.get(REPEAT_PARAMS); | ||
| 99 | - String preParams = (String) preMap.get(REPEAT_PARAMS); | ||
| 100 | - return nowParams.equals(preParams); | ||
| 101 | - } | ||
| 102 | - | ||
| 103 | - /** | ||
| 104 | - * 判断两次间隔时间 | ||
| 105 | - */ | ||
| 106 | - private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap) { | ||
| 107 | - long time1 = (Long) nowMap.get(REPEAT_TIME); | ||
| 108 | - long time2 = (Long) preMap.get(REPEAT_TIME); | ||
| 109 | - if ((time1 - time2) < (this.intervalTime * 1000)) { | ||
| 110 | - return true; | ||
| 111 | - } | ||
| 112 | - return false; | ||
| 113 | - } | ||
| 114 | -} | 1 | +package com.ruoyi.framework.interceptor.impl; |
| 2 | + | ||
| 3 | +import java.util.HashMap; | ||
| 4 | +import java.util.Map; | ||
| 5 | +import java.util.concurrent.TimeUnit; | ||
| 6 | +import javax.servlet.http.HttpServletRequest; | ||
| 7 | + | ||
| 8 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 9 | +import org.springframework.beans.factory.annotation.Value; | ||
| 10 | +import org.springframework.stereotype.Component; | ||
| 11 | +import com.alibaba.fastjson.JSONObject; | ||
| 12 | +import com.ruoyi.common.constant.Constants; | ||
| 13 | +import com.ruoyi.common.core.redis.RedisCache; | ||
| 14 | +import com.ruoyi.common.filter.RepeatedlyRequestWrapper; | ||
| 15 | +import com.ruoyi.common.utils.StringUtils; | ||
| 16 | +import com.ruoyi.common.utils.http.HttpHelper; | ||
| 17 | +import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * 判断请求url和数据是否和上一次相同, | ||
| 21 | + * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。 | ||
| 22 | + * | ||
| 23 | + * @author ruoyi | ||
| 24 | + */ | ||
| 25 | +@Component | ||
| 26 | +public class SameUrlDataInterceptor extends RepeatSubmitInterceptor { | ||
| 27 | + public final String REPEAT_PARAMS = "repeatParams"; | ||
| 28 | + | ||
| 29 | + public final String REPEAT_TIME = "repeatTime"; | ||
| 30 | + | ||
| 31 | + // 令牌自定义标识 | ||
| 32 | + @Value("${token.header}") | ||
| 33 | + private String header; | ||
| 34 | + | ||
| 35 | + @Autowired | ||
| 36 | + private RedisCache redisCache; | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 间隔时间,单位:秒 默认10秒 | ||
| 40 | + * <p> | ||
| 41 | + * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据 | ||
| 42 | + */ | ||
| 43 | + private int intervalTime = 10; | ||
| 44 | + | ||
| 45 | + public void setIntervalTime(int intervalTime) { | ||
| 46 | + this.intervalTime = intervalTime; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + @SuppressWarnings("unchecked") | ||
| 50 | + @Override | ||
| 51 | + public boolean isRepeatSubmit(HttpServletRequest request) { | ||
| 52 | + String nowParams = ""; | ||
| 53 | + if (request instanceof RepeatedlyRequestWrapper) { | ||
| 54 | + RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request; | ||
| 55 | + nowParams = HttpHelper.getBodyString(repeatedlyRequest); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + // body参数为空,获取Parameter的数据 | ||
| 59 | + if (StringUtils.isEmpty(nowParams)) { | ||
| 60 | + nowParams = JSONObject.toJSONString(request.getParameterMap()); | ||
| 61 | + } | ||
| 62 | + Map<String, Object> nowDataMap = new HashMap<String, Object>(); | ||
| 63 | + nowDataMap.put(REPEAT_PARAMS, nowParams); | ||
| 64 | + nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); | ||
| 65 | + | ||
| 66 | + // 请求地址(作为存放cache的key值) | ||
| 67 | + String url = request.getRequestURI(); | ||
| 68 | + | ||
| 69 | + // 唯一值(没有消息头则使用请求地址) | ||
| 70 | + String submitKey = request.getHeader(header); | ||
| 71 | + if (StringUtils.isEmpty(submitKey)) { | ||
| 72 | + submitKey = url; | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + // 唯一标识(指定key + 消息头) | ||
| 76 | + String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey; | ||
| 77 | + | ||
| 78 | + Object sessionObj = redisCache.getCacheObject(cache_repeat_key); | ||
| 79 | + if (sessionObj != null) { | ||
| 80 | + Map<String, Object> sessionMap = (Map<String, Object>) sessionObj; | ||
| 81 | + if (sessionMap.containsKey(url)) { | ||
| 82 | + Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url); | ||
| 83 | + if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap)) { | ||
| 84 | + return true; | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + Map<String, Object> cacheMap = new HashMap<String, Object>(); | ||
| 89 | + cacheMap.put(url, nowDataMap); | ||
| 90 | + redisCache.setCacheObject(cache_repeat_key, cacheMap, intervalTime, TimeUnit.SECONDS); | ||
| 91 | + return false; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + /** | ||
| 95 | + * 判断参数是否相同 | ||
| 96 | + */ | ||
| 97 | + private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap) { | ||
| 98 | + String nowParams = (String) nowMap.get(REPEAT_PARAMS); | ||
| 99 | + String preParams = (String) preMap.get(REPEAT_PARAMS); | ||
| 100 | + return nowParams.equals(preParams); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + /** | ||
| 104 | + * 判断两次间隔时间 | ||
| 105 | + */ | ||
| 106 | + private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap) { | ||
| 107 | + long time1 = (Long) nowMap.get(REPEAT_TIME); | ||
| 108 | + long time2 = (Long) preMap.get(REPEAT_TIME); | ||
| 109 | + if ((time1 - time2) < (this.intervalTime * 1000)) { | ||
| 110 | + return true; | ||
| 111 | + } | ||
| 112 | + return false; | ||
| 113 | + } | ||
| 114 | +} |
ruoyi-admin/src/main/resources/application-druid.yml renamed to ruoyi-common/src/main/resources/application-druid.yml
| 1 | -# 数据源配置 | ||
| 2 | -spring: | ||
| 3 | - datasource: | ||
| 4 | - type: com.alibaba.druid.pool.DruidDataSource | ||
| 5 | - driverClassName: com.mysql.cj.jdbc.Driver | ||
| 6 | - druid: | ||
| 7 | - # 主库数据源 | ||
| 8 | - master: | ||
| 9 | - url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 | ||
| 10 | - username: root | ||
| 11 | - password: password | ||
| 12 | - # 从库数据源 | ||
| 13 | - slave: | ||
| 14 | - # 从数据源开关/默认关闭 | ||
| 15 | - enabled: false | ||
| 16 | - url: | ||
| 17 | - username: | ||
| 18 | - password: | ||
| 19 | - # 初始连接数 | ||
| 20 | - initialSize: 5 | ||
| 21 | - # 最小连接池数量 | ||
| 22 | - minIdle: 10 | ||
| 23 | - # 最大连接池数量 | ||
| 24 | - maxActive: 20 | ||
| 25 | - # 配置获取连接等待超时的时间 | ||
| 26 | - maxWait: 60000 | ||
| 27 | - # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 | ||
| 28 | - timeBetweenEvictionRunsMillis: 60000 | ||
| 29 | - # 配置一个连接在池中最小生存的时间,单位是毫秒 | ||
| 30 | - minEvictableIdleTimeMillis: 300000 | ||
| 31 | - # 配置一个连接在池中最大生存的时间,单位是毫秒 | ||
| 32 | - maxEvictableIdleTimeMillis: 900000 | ||
| 33 | - # 配置检测连接是否有效 | ||
| 34 | - validationQuery: SELECT 1 FROM DUAL | ||
| 35 | - testWhileIdle: true | ||
| 36 | - testOnBorrow: false | ||
| 37 | - testOnReturn: false | ||
| 38 | - webStatFilter: | ||
| 39 | - enabled: true | ||
| 40 | - statViewServlet: | ||
| 41 | - enabled: true | ||
| 42 | - # 设置白名单,不填则允许所有访问 | ||
| 43 | - allow: | ||
| 44 | - url-pattern: /druid/* | ||
| 45 | - # 控制台管理用户名和密码 | ||
| 46 | - login-username: | ||
| 47 | - login-password: | ||
| 48 | - filter: | ||
| 49 | - stat: | ||
| 50 | - enabled: true | ||
| 51 | - # 慢SQL记录 | ||
| 52 | - log-slow-sql: true | ||
| 53 | - slow-sql-millis: 1000 | ||
| 54 | - merge-sql: true | ||
| 55 | - wall: | ||
| 56 | - config: | 1 | +# 数据源配置 |
| 2 | +spring: | ||
| 3 | + datasource: | ||
| 4 | + type: com.alibaba.druid.pool.DruidDataSource | ||
| 5 | + driverClassName: com.mysql.cj.jdbc.Driver | ||
| 6 | + druid: | ||
| 7 | + # 主库数据源 | ||
| 8 | + master: | ||
| 9 | + url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 | ||
| 10 | + username: root | ||
| 11 | + password: password | ||
| 12 | + # 从库数据源 | ||
| 13 | + slave: | ||
| 14 | + # 从数据源开关/默认关闭 | ||
| 15 | + enabled: false | ||
| 16 | + url: | ||
| 17 | + username: | ||
| 18 | + password: | ||
| 19 | + # 初始连接数 | ||
| 20 | + initialSize: 5 | ||
| 21 | + # 最小连接池数量 | ||
| 22 | + minIdle: 10 | ||
| 23 | + # 最大连接池数量 | ||
| 24 | + maxActive: 20 | ||
| 25 | + # 配置获取连接等待超时的时间 | ||
| 26 | + maxWait: 60000 | ||
| 27 | + # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 | ||
| 28 | + timeBetweenEvictionRunsMillis: 60000 | ||
| 29 | + # 配置一个连接在池中最小生存的时间,单位是毫秒 | ||
| 30 | + minEvictableIdleTimeMillis: 300000 | ||
| 31 | + # 配置一个连接在池中最大生存的时间,单位是毫秒 | ||
| 32 | + maxEvictableIdleTimeMillis: 900000 | ||
| 33 | + # 配置检测连接是否有效 | ||
| 34 | + validationQuery: SELECT 1 FROM DUAL | ||
| 35 | + testWhileIdle: true | ||
| 36 | + testOnBorrow: false | ||
| 37 | + testOnReturn: false | ||
| 38 | + webStatFilter: | ||
| 39 | + enabled: true | ||
| 40 | + statViewServlet: | ||
| 41 | + enabled: true | ||
| 42 | + # 设置白名单,不填则允许所有访问 | ||
| 43 | + allow: | ||
| 44 | + url-pattern: /druid/* | ||
| 45 | + # 控制台管理用户名和密码 | ||
| 46 | + login-username: | ||
| 47 | + login-password: | ||
| 48 | + filter: | ||
| 49 | + stat: | ||
| 50 | + enabled: true | ||
| 51 | + # 慢SQL记录 | ||
| 52 | + log-slow-sql: true | ||
| 53 | + slow-sql-millis: 1000 | ||
| 54 | + merge-sql: true | ||
| 55 | + wall: | ||
| 56 | + config: | ||
| 57 | multi-statement-allow: true | 57 | multi-statement-allow: true |
| 58 | \ No newline at end of file | 58 | \ No newline at end of file |
ruoyi-admin/src/main/resources/application.yml renamed to ruoyi-common/src/main/resources/application.yml
| 1 | -# 项目相关配置 | ||
| 2 | -ruoyi: | ||
| 3 | - # 名称 | ||
| 4 | - name: RuoYi | ||
| 5 | - # 版本 | ||
| 6 | - version: 3.3.0 | ||
| 7 | - # 版权年份 | ||
| 8 | - copyrightYear: 2020 | ||
| 9 | - # 实例演示开关 | ||
| 10 | - demoEnabled: true | ||
| 11 | - # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) | ||
| 12 | - profile: D:/ruoyi/uploadPath | ||
| 13 | - # 获取ip地址开关 | ||
| 14 | - addressEnabled: false | ||
| 15 | - | ||
| 16 | -# 开发环境配置 | ||
| 17 | -server: | ||
| 18 | - # 服务器的HTTP端口,默认为8080 | ||
| 19 | - port: 8080 | ||
| 20 | - servlet: | ||
| 21 | - # 应用的访问路径 | ||
| 22 | - context-path: / | ||
| 23 | - tomcat: | ||
| 24 | - # tomcat的URI编码 | ||
| 25 | - uri-encoding: UTF-8 | ||
| 26 | - # tomcat最大线程数,默认为200 | ||
| 27 | - max-threads: 800 | ||
| 28 | - # Tomcat启动初始化的线程数,默认值25 | ||
| 29 | - min-spare-threads: 30 | ||
| 30 | - | ||
| 31 | -# 日志配置 | ||
| 32 | -logging: | ||
| 33 | - level: | ||
| 34 | - com.ruoyi: debug | ||
| 35 | - org.springframework: warn | ||
| 36 | - | ||
| 37 | -# 防止XSS攻击 | ||
| 38 | -xss: | ||
| 39 | - # 过滤开关 | ||
| 40 | - enabled: true | ||
| 41 | - # 排除链接(多个用逗号分隔) | ||
| 42 | - excludes: /system/notice/* | ||
| 43 | - # 匹配链接 | ||
| 44 | - urlPatterns: /system/*,/monitor/*,/tool/* | 1 | +# 项目相关配置 |
| 2 | +ruoyi: | ||
| 3 | + # 名称 | ||
| 4 | + name: RuoYi | ||
| 5 | + # 版本 | ||
| 6 | + version: 3.3.0 | ||
| 7 | + # 版权年份 | ||
| 8 | + copyrightYear: 2020 | ||
| 9 | + # 实例演示开关 | ||
| 10 | + demoEnabled: true | ||
| 11 | + # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) | ||
| 12 | + profile: D:/ruoyi/uploadPath | ||
| 13 | + # 获取ip地址开关 | ||
| 14 | + addressEnabled: false | ||
| 15 | + | ||
| 16 | +# 开发环境配置 | ||
| 17 | +server: | ||
| 18 | + # 服务器的HTTP端口,默认为8080 | ||
| 19 | + port: 8080 | ||
| 20 | + servlet: | ||
| 21 | + # 应用的访问路径 | ||
| 22 | + context-path: / | ||
| 23 | + tomcat: | ||
| 24 | + # tomcat的URI编码 | ||
| 25 | + uri-encoding: UTF-8 | ||
| 26 | + # tomcat最大线程数,默认为200 | ||
| 27 | + max-threads: 800 | ||
| 28 | + # Tomcat启动初始化的线程数,默认值25 | ||
| 29 | + min-spare-threads: 30 | ||
| 30 | + | ||
| 31 | +# 日志配置 | ||
| 32 | +logging: | ||
| 33 | + level: | ||
| 34 | + com.ruoyi: debug | ||
| 35 | + org.springframework: warn | ||
| 36 | + | ||
| 37 | +# 防止XSS攻击 | ||
| 38 | +xss: | ||
| 39 | + # 过滤开关 | ||
| 40 | + enabled: true | ||
| 41 | + # 排除链接(多个用逗号分隔) | ||
| 42 | + excludes: /system/notice/* | ||
| 43 | + # 匹配链接 | ||
| 44 | + urlPatterns: /system/*,/monitor/*,/tool/* |
ruoyi-admin/src/main/resources/i18n/messages.properties renamed to ruoyi-common/src/main/resources/i18n/messages.properties
| 1 | -#错误消息 | ||
| 2 | -not.null=* 必须填写 | ||
| 3 | -user.jcaptcha.error=验证码错误 | ||
| 4 | -user.jcaptcha.expire=验证码已失效 | ||
| 5 | -user.not.exists=用户不存在/密码错误 | ||
| 6 | -user.password.not.match=用户不存在/密码错误 | ||
| 7 | -user.password.retry.limit.count=密码输入错误{0}次 | ||
| 8 | -user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟 | ||
| 9 | -user.password.delete=对不起,您的账号已被删除 | ||
| 10 | -user.blocked=用户已封禁,请联系管理员 | ||
| 11 | -role.blocked=角色已封禁,请联系管理员 | ||
| 12 | -user.logout.success=退出成功 | ||
| 13 | - | ||
| 14 | -length.not.valid=长度必须在{min}到{max}个字符之间 | ||
| 15 | - | ||
| 16 | -user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 | ||
| 17 | -user.password.not.valid=* 5-50个字符 | ||
| 18 | - | ||
| 19 | -user.email.not.valid=邮箱格式错误 | ||
| 20 | -user.mobile.phone.number.not.valid=手机号格式错误 | ||
| 21 | -user.login.success=登录成功 | ||
| 22 | -user.notfound=请重新登录 | ||
| 23 | -user.forcelogout=管理员强制退出,请重新登录 | ||
| 24 | -user.unknown.error=未知错误,请重新登录 | ||
| 25 | - | ||
| 26 | -##文件上传消息 | ||
| 27 | -upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB! | ||
| 28 | -upload.filename.exceed.length=上传的文件名最长{0}个字符 | ||
| 29 | - | ||
| 30 | -##权限 | ||
| 31 | -no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] | ||
| 32 | -no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] | ||
| 33 | -no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] | ||
| 34 | -no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] | ||
| 35 | -no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] | ||
| 36 | -no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] | 1 | +#错误消息 |
| 2 | +not.null=* 必须填写 | ||
| 3 | +user.jcaptcha.error=验证码错误 | ||
| 4 | +user.jcaptcha.expire=验证码已失效 | ||
| 5 | +user.not.exists=用户不存在/密码错误 | ||
| 6 | +user.password.not.match=用户不存在/密码错误 | ||
| 7 | +user.password.retry.limit.count=密码输入错误{0}次 | ||
| 8 | +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟 | ||
| 9 | +user.password.delete=对不起,您的账号已被删除 | ||
| 10 | +user.blocked=用户已封禁,请联系管理员 | ||
| 11 | +role.blocked=角色已封禁,请联系管理员 | ||
| 12 | +user.logout.success=退出成功 | ||
| 13 | + | ||
| 14 | +length.not.valid=长度必须在{min}到{max}个字符之间 | ||
| 15 | + | ||
| 16 | +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 | ||
| 17 | +user.password.not.valid=* 5-50个字符 | ||
| 18 | + | ||
| 19 | +user.email.not.valid=邮箱格式错误 | ||
| 20 | +user.mobile.phone.number.not.valid=手机号格式错误 | ||
| 21 | +user.login.success=登录成功 | ||
| 22 | +user.notfound=请重新登录 | ||
| 23 | +user.forcelogout=管理员强制退出,请重新登录 | ||
| 24 | +user.unknown.error=未知错误,请重新登录 | ||
| 25 | + | ||
| 26 | +##文件上传消息 | ||
| 27 | +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB! | ||
| 28 | +upload.filename.exceed.length=上传的文件名最长{0}个字符 | ||
| 29 | + | ||
| 30 | +##权限 | ||
| 31 | +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] | ||
| 32 | +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] | ||
| 33 | +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] | ||
| 34 | +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] | ||
| 35 | +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] | ||
| 36 | +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] |
ruoyi-admin/src/main/resources/logback.xml renamed to ruoyi-common/src/main/resources/logback.xml
| 1 | -<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | -<configuration> | ||
| 3 | - <!-- 日志存放路径 --> | ||
| 4 | - <property name="log.path" value="/home/ruoyi/logs" /> | ||
| 5 | - <!-- 日志输出格式 --> | ||
| 6 | - <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> | ||
| 7 | - | ||
| 8 | - <!-- 控制台输出 --> | ||
| 9 | - <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> | ||
| 10 | - <encoder> | ||
| 11 | - <pattern>${log.pattern}</pattern> | ||
| 12 | - </encoder> | ||
| 13 | - </appender> | ||
| 14 | - | ||
| 15 | - <!-- 系统日志输出 --> | ||
| 16 | - <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||
| 17 | - <file>${log.path}/sys-info.log</file> | ||
| 18 | - <!-- 循环政策:基于时间创建日志文件 --> | ||
| 19 | - <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||
| 20 | - <!-- 日志文件名格式 --> | ||
| 21 | - <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern> | ||
| 22 | - <!-- 日志最大的历史 60天 --> | ||
| 23 | - <maxHistory>60</maxHistory> | ||
| 24 | - </rollingPolicy> | ||
| 25 | - <encoder> | ||
| 26 | - <pattern>${log.pattern}</pattern> | ||
| 27 | - </encoder> | ||
| 28 | - <filter class="ch.qos.logback.classic.filter.LevelFilter"> | ||
| 29 | - <!-- 过滤的级别 --> | ||
| 30 | - <level>INFO</level> | ||
| 31 | - <!-- 匹配时的操作:接收(记录) --> | ||
| 32 | - <onMatch>ACCEPT</onMatch> | ||
| 33 | - <!-- 不匹配时的操作:拒绝(不记录) --> | ||
| 34 | - <onMismatch>DENY</onMismatch> | ||
| 35 | - </filter> | ||
| 36 | - </appender> | ||
| 37 | - | ||
| 38 | - <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||
| 39 | - <file>${log.path}/sys-error.log</file> | ||
| 40 | - <!-- 循环政策:基于时间创建日志文件 --> | ||
| 41 | - <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||
| 42 | - <!-- 日志文件名格式 --> | ||
| 43 | - <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern> | ||
| 44 | - <!-- 日志最大的历史 60天 --> | ||
| 45 | - <maxHistory>60</maxHistory> | ||
| 46 | - </rollingPolicy> | ||
| 47 | - <encoder> | ||
| 48 | - <pattern>${log.pattern}</pattern> | ||
| 49 | - </encoder> | ||
| 50 | - <filter class="ch.qos.logback.classic.filter.LevelFilter"> | ||
| 51 | - <!-- 过滤的级别 --> | ||
| 52 | - <level>ERROR</level> | ||
| 53 | - <!-- 匹配时的操作:接收(记录) --> | ||
| 54 | - <onMatch>ACCEPT</onMatch> | ||
| 55 | - <!-- 不匹配时的操作:拒绝(不记录) --> | ||
| 56 | - <onMismatch>DENY</onMismatch> | ||
| 57 | - </filter> | ||
| 58 | - </appender> | ||
| 59 | - | ||
| 60 | - <!-- 用户访问日志输出 --> | ||
| 61 | - <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||
| 62 | - <file>${log.path}/sys-user.log</file> | ||
| 63 | - <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||
| 64 | - <!-- 按天回滚 daily --> | ||
| 65 | - <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern> | ||
| 66 | - <!-- 日志最大的历史 60天 --> | ||
| 67 | - <maxHistory>60</maxHistory> | ||
| 68 | - </rollingPolicy> | ||
| 69 | - <encoder> | ||
| 70 | - <pattern>${log.pattern}</pattern> | ||
| 71 | - </encoder> | ||
| 72 | - </appender> | ||
| 73 | - | ||
| 74 | - <!-- 系统模块日志级别控制 --> | ||
| 75 | - <logger name="com.ruoyi" level="info" /> | ||
| 76 | - <!-- Spring日志级别控制 --> | ||
| 77 | - <logger name="org.springframework" level="warn" /> | ||
| 78 | - | ||
| 79 | - <root level="info"> | ||
| 80 | - <appender-ref ref="console" /> | ||
| 81 | - </root> | ||
| 82 | - | ||
| 83 | - <!--系统操作日志--> | ||
| 84 | - <root level="info"> | ||
| 85 | - <appender-ref ref="file_info" /> | ||
| 86 | - <appender-ref ref="file_error" /> | ||
| 87 | - </root> | ||
| 88 | - | ||
| 89 | - <!--系统用户操作日志--> | ||
| 90 | - <logger name="sys-user" level="info"> | ||
| 91 | - <appender-ref ref="sys-user"/> | ||
| 92 | - </logger> | 1 | +<?xml version="1.0" encoding="UTF-8"?> |
| 2 | +<configuration> | ||
| 3 | + <!-- 日志存放路径 --> | ||
| 4 | + <property name="log.path" value="/home/ruoyi/logs" /> | ||
| 5 | + <!-- 日志输出格式 --> | ||
| 6 | + <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> | ||
| 7 | + | ||
| 8 | + <!-- 控制台输出 --> | ||
| 9 | + <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> | ||
| 10 | + <encoder> | ||
| 11 | + <pattern>${log.pattern}</pattern> | ||
| 12 | + </encoder> | ||
| 13 | + </appender> | ||
| 14 | + | ||
| 15 | + <!-- 系统日志输出 --> | ||
| 16 | + <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||
| 17 | + <file>${log.path}/sys-info.log</file> | ||
| 18 | + <!-- 循环政策:基于时间创建日志文件 --> | ||
| 19 | + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||
| 20 | + <!-- 日志文件名格式 --> | ||
| 21 | + <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern> | ||
| 22 | + <!-- 日志最大的历史 60天 --> | ||
| 23 | + <maxHistory>60</maxHistory> | ||
| 24 | + </rollingPolicy> | ||
| 25 | + <encoder> | ||
| 26 | + <pattern>${log.pattern}</pattern> | ||
| 27 | + </encoder> | ||
| 28 | + <filter class="ch.qos.logback.classic.filter.LevelFilter"> | ||
| 29 | + <!-- 过滤的级别 --> | ||
| 30 | + <level>INFO</level> | ||
| 31 | + <!-- 匹配时的操作:接收(记录) --> | ||
| 32 | + <onMatch>ACCEPT</onMatch> | ||
| 33 | + <!-- 不匹配时的操作:拒绝(不记录) --> | ||
| 34 | + <onMismatch>DENY</onMismatch> | ||
| 35 | + </filter> | ||
| 36 | + </appender> | ||
| 37 | + | ||
| 38 | + <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||
| 39 | + <file>${log.path}/sys-error.log</file> | ||
| 40 | + <!-- 循环政策:基于时间创建日志文件 --> | ||
| 41 | + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||
| 42 | + <!-- 日志文件名格式 --> | ||
| 43 | + <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern> | ||
| 44 | + <!-- 日志最大的历史 60天 --> | ||
| 45 | + <maxHistory>60</maxHistory> | ||
| 46 | + </rollingPolicy> | ||
| 47 | + <encoder> | ||
| 48 | + <pattern>${log.pattern}</pattern> | ||
| 49 | + </encoder> | ||
| 50 | + <filter class="ch.qos.logback.classic.filter.LevelFilter"> | ||
| 51 | + <!-- 过滤的级别 --> | ||
| 52 | + <level>ERROR</level> | ||
| 53 | + <!-- 匹配时的操作:接收(记录) --> | ||
| 54 | + <onMatch>ACCEPT</onMatch> | ||
| 55 | + <!-- 不匹配时的操作:拒绝(不记录) --> | ||
| 56 | + <onMismatch>DENY</onMismatch> | ||
| 57 | + </filter> | ||
| 58 | + </appender> | ||
| 59 | + | ||
| 60 | + <!-- 用户访问日志输出 --> | ||
| 61 | + <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||
| 62 | + <file>${log.path}/sys-user.log</file> | ||
| 63 | + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||
| 64 | + <!-- 按天回滚 daily --> | ||
| 65 | + <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern> | ||
| 66 | + <!-- 日志最大的历史 60天 --> | ||
| 67 | + <maxHistory>60</maxHistory> | ||
| 68 | + </rollingPolicy> | ||
| 69 | + <encoder> | ||
| 70 | + <pattern>${log.pattern}</pattern> | ||
| 71 | + </encoder> | ||
| 72 | + </appender> | ||
| 73 | + | ||
| 74 | + <!-- 系统模块日志级别控制 --> | ||
| 75 | + <logger name="com.ruoyi" level="info" /> | ||
| 76 | + <!-- Spring日志级别控制 --> | ||
| 77 | + <logger name="org.springframework" level="warn" /> | ||
| 78 | + | ||
| 79 | + <root level="info"> | ||
| 80 | + <appender-ref ref="console" /> | ||
| 81 | + </root> | ||
| 82 | + | ||
| 83 | + <!--系统操作日志--> | ||
| 84 | + <root level="info"> | ||
| 85 | + <appender-ref ref="file_info" /> | ||
| 86 | + <appender-ref ref="file_error" /> | ||
| 87 | + </root> | ||
| 88 | + | ||
| 89 | + <!--系统用户操作日志--> | ||
| 90 | + <logger name="sys-user" level="info"> | ||
| 91 | + <appender-ref ref="sys-user"/> | ||
| 92 | + </logger> | ||
| 93 | </configuration> | 93 | </configuration> |
| 94 | \ No newline at end of file | 94 | \ No newline at end of file |
ruoyi-ui/src/api/monitor/online.js renamed to ruoyi-ui/src/api/system/session.js
| 1 | -import request from '@/utils/request' | ||
| 2 | - | ||
| 3 | -// 查询在线用户列表 | ||
| 4 | -export function list(query) { | ||
| 5 | - return request({ | ||
| 6 | - url: '/monitor/online/list', | ||
| 7 | - method: 'get', | ||
| 8 | - params: query | ||
| 9 | - }) | ||
| 10 | -} | ||
| 11 | - | ||
| 12 | -// 强退用户 | ||
| 13 | -export function forceLogout(tokenId) { | ||
| 14 | - return request({ | ||
| 15 | - url: '/monitor/online/' + tokenId, | ||
| 16 | - method: 'delete' | ||
| 17 | - }) | ||
| 18 | -} | 1 | +import request from '@/utils/request' |
| 2 | + | ||
| 3 | +// 查询在线用户列表 | ||
| 4 | +export function list(query) { | ||
| 5 | + return request({ | ||
| 6 | + url: '/system/user-session/page', | ||
| 7 | + method: 'get', | ||
| 8 | + params: query | ||
| 9 | + }) | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +// 强退用户 | ||
| 13 | +export function forceLogout(tokenId) { | ||
| 14 | + return request({ | ||
| 15 | + url: '/system/user-session/delete?id=' + tokenId, | ||
| 16 | + method: 'delete' | ||
| 17 | + }) | ||
| 18 | +} |
ruoyi-ui/src/views/monitor/online/index.vue renamed to ruoyi-ui/src/views/system/session/index.vue
| 1 | -<template> | ||
| 2 | - <div class="app-container"> | ||
| 3 | - <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px"> | ||
| 4 | - <el-form-item label="登录地址" prop="ipaddr"> | ||
| 5 | - <el-input | ||
| 6 | - v-model="queryParams.ipaddr" | ||
| 7 | - placeholder="请输入登录地址" | ||
| 8 | - clearable | ||
| 9 | - size="small" | ||
| 10 | - @keyup.enter.native="handleQuery" | ||
| 11 | - /> | ||
| 12 | - </el-form-item> | ||
| 13 | - <el-form-item label="用户名称" prop="userName"> | ||
| 14 | - <el-input | ||
| 15 | - v-model="queryParams.userName" | ||
| 16 | - placeholder="请输入用户名称" | ||
| 17 | - clearable | ||
| 18 | - size="small" | ||
| 19 | - @keyup.enter.native="handleQuery" | ||
| 20 | - /> | ||
| 21 | - </el-form-item> | ||
| 22 | - <el-form-item> | ||
| 23 | - <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> | ||
| 24 | - <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> | ||
| 25 | - </el-form-item> | ||
| 26 | - | ||
| 27 | - </el-form> | ||
| 28 | - <el-table | ||
| 29 | - v-loading="loading" | ||
| 30 | - :data="list.slice((pageNum-1)*pageSize,pageNum*pageSize)" | ||
| 31 | - style="width: 100%;" | ||
| 32 | - > | ||
| 33 | - <el-table-column label="序号" type="index" align="center"> | ||
| 34 | - <template slot-scope="scope"> | ||
| 35 | - <span>{{(pageNum - 1) * pageSize + scope.$index + 1}}</span> | ||
| 36 | - </template> | ||
| 37 | - </el-table-column> | ||
| 38 | - <el-table-column label="会话编号" align="center" prop="tokenId" :show-overflow-tooltip="true" /> | ||
| 39 | - <el-table-column label="登录名称" align="center" prop="userName" :show-overflow-tooltip="true" /> | ||
| 40 | - <el-table-column label="部门名称" align="center" prop="deptName" /> | ||
| 41 | - <el-table-column label="主机" align="center" prop="ipaddr" :show-overflow-tooltip="true" /> | ||
| 42 | - <el-table-column label="登录地点" align="center" prop="loginLocation" :show-overflow-tooltip="true" /> | ||
| 43 | - <el-table-column label="浏览器" align="center" prop="browser" /> | ||
| 44 | - <el-table-column label="操作系统" align="center" prop="os" /> | ||
| 45 | - <el-table-column label="登录时间" align="center" prop="loginTime" width="180"> | ||
| 46 | - <template slot-scope="scope"> | ||
| 47 | - <span>{{ parseTime(scope.row.loginTime) }}</span> | ||
| 48 | - </template> | ||
| 49 | - </el-table-column> | ||
| 50 | - <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | ||
| 51 | - <template slot-scope="scope"> | ||
| 52 | - <el-button | ||
| 53 | - size="mini" | ||
| 54 | - type="text" | ||
| 55 | - icon="el-icon-delete" | ||
| 56 | - @click="handleForceLogout(scope.row)" | ||
| 57 | - v-hasPermi="['monitor:online:forceLogout']" | ||
| 58 | - >强退</el-button> | ||
| 59 | - </template> | ||
| 60 | - </el-table-column> | ||
| 61 | - </el-table> | ||
| 62 | - | ||
| 63 | - <pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" /> | ||
| 64 | - </div> | ||
| 65 | -</template> | ||
| 66 | - | ||
| 67 | -<script> | ||
| 68 | -import { list, forceLogout } from "@/api/monitor/online"; | ||
| 69 | - | ||
| 70 | -export default { | ||
| 71 | - name: "Online", | ||
| 72 | - data() { | ||
| 73 | - return { | ||
| 74 | - // 遮罩层 | ||
| 75 | - loading: true, | ||
| 76 | - // 总条数 | ||
| 77 | - total: 0, | ||
| 78 | - // 表格数据 | ||
| 79 | - list: [], | ||
| 80 | - pageNum: 1, | ||
| 81 | - pageSize: 10, | ||
| 82 | - // 查询参数 | ||
| 83 | - queryParams: { | ||
| 84 | - ipaddr: undefined, | ||
| 85 | - userName: undefined | ||
| 86 | - } | ||
| 87 | - }; | ||
| 88 | - }, | ||
| 89 | - created() { | ||
| 90 | - this.getList(); | ||
| 91 | - }, | ||
| 92 | - methods: { | ||
| 93 | - /** 查询登录日志列表 */ | ||
| 94 | - getList() { | ||
| 95 | - this.loading = true; | ||
| 96 | - list(this.queryParams).then(response => { | ||
| 97 | - this.list = response.rows; | ||
| 98 | - this.total = response.total; | ||
| 99 | - this.loading = false; | ||
| 100 | - }); | ||
| 101 | - }, | ||
| 102 | - /** 搜索按钮操作 */ | ||
| 103 | - handleQuery() { | ||
| 104 | - this.pageNum = 1; | ||
| 105 | - this.getList(); | ||
| 106 | - }, | ||
| 107 | - /** 重置按钮操作 */ | ||
| 108 | - resetQuery() { | ||
| 109 | - this.resetForm("queryForm"); | ||
| 110 | - this.handleQuery(); | ||
| 111 | - }, | ||
| 112 | - /** 强退按钮操作 */ | ||
| 113 | - handleForceLogout(row) { | ||
| 114 | - this.$confirm('是否确认强退名称为"' + row.userName + '"的数据项?', "警告", { | ||
| 115 | - confirmButtonText: "确定", | ||
| 116 | - cancelButtonText: "取消", | ||
| 117 | - type: "warning" | ||
| 118 | - }).then(function() { | ||
| 119 | - return forceLogout(row.tokenId); | ||
| 120 | - }).then(() => { | ||
| 121 | - this.getList(); | ||
| 122 | - this.msgSuccess("强退成功"); | ||
| 123 | - }) | ||
| 124 | - } | ||
| 125 | - } | ||
| 126 | -}; | ||
| 127 | -</script> | ||
| 128 | - | 1 | +<template> |
| 2 | + <div class="app-container"> | ||
| 3 | + <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px"> | ||
| 4 | + <el-form-item label="登录地址" prop="userIp"> | ||
| 5 | + <el-input | ||
| 6 | + v-model="queryParams.userIp" | ||
| 7 | + placeholder="请输入登录地址" | ||
| 8 | + clearable | ||
| 9 | + size="small" | ||
| 10 | + @keyup.enter.native="handleQuery" | ||
| 11 | + /> | ||
| 12 | + </el-form-item> | ||
| 13 | + <el-form-item label="用户名称" prop="username"> | ||
| 14 | + <el-input | ||
| 15 | + v-model="queryParams.username" | ||
| 16 | + placeholder="请输入用户名称" | ||
| 17 | + clearable | ||
| 18 | + size="small" | ||
| 19 | + @keyup.enter.native="handleQuery" | ||
| 20 | + /> | ||
| 21 | + </el-form-item> | ||
| 22 | + <el-form-item> | ||
| 23 | + <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> | ||
| 24 | + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> | ||
| 25 | + </el-form-item> | ||
| 26 | + | ||
| 27 | + </el-form> | ||
| 28 | + <el-table | ||
| 29 | + v-loading="loading" | ||
| 30 | + :data="list" | ||
| 31 | + style="width: 100%;" | ||
| 32 | + > | ||
| 33 | + <el-table-column label="会话编号" align="center" prop="id" width="300" /> | ||
| 34 | + <el-table-column label="登录名称" align="center" prop="username" width="100" /> | ||
| 35 | + <el-table-column label="部门名称" align="center" prop="deptName" width="100" /> | ||
| 36 | + <el-table-column label="登陆地址" align="center" prop="userIp" width="100" /> | ||
| 37 | + <el-table-column label="userAgent" align="center" prop="userAgent" :show-overflow-tooltip="true" /> | ||
| 38 | + <el-table-column label="登录时间" align="center" prop="createTime" width="180"> | ||
| 39 | + <template slot-scope="scope"> | ||
| 40 | + <span>{{ parseTime(scope.row.createTime) }}</span> | ||
| 41 | + </template> | ||
| 42 | + </el-table-column> | ||
| 43 | + <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | ||
| 44 | + <template slot-scope="scope"> | ||
| 45 | + <el-button | ||
| 46 | + size="mini" | ||
| 47 | + type="text" | ||
| 48 | + icon="el-icon-delete" | ||
| 49 | + @click="handleForceLogout(scope.row)" | ||
| 50 | + v-hasPermi="['system:user-session:delete']" | ||
| 51 | + >强退</el-button> | ||
| 52 | + </template> | ||
| 53 | + </el-table-column> | ||
| 54 | + </el-table> | ||
| 55 | + | ||
| 56 | + <pagination v-show="total>0" :total="total" :page.sync="pageNo" :limit.sync="pageSize" /> | ||
| 57 | + </div> | ||
| 58 | +</template> | ||
| 59 | + | ||
| 60 | +<script> | ||
| 61 | +import { list, forceLogout } from "@/api/system/session"; | ||
| 62 | + | ||
| 63 | +export default { | ||
| 64 | + name: "Online", | ||
| 65 | + data() { | ||
| 66 | + return { | ||
| 67 | + // 遮罩层 | ||
| 68 | + loading: true, | ||
| 69 | + // 总条数 | ||
| 70 | + total: 0, | ||
| 71 | + // 表格数据 | ||
| 72 | + list: [], | ||
| 73 | + // 查询参数 | ||
| 74 | + queryParams: { | ||
| 75 | + pageNo: 1, | ||
| 76 | + pageSize: 10, | ||
| 77 | + userIp: undefined, | ||
| 78 | + username: undefined | ||
| 79 | + } | ||
| 80 | + }; | ||
| 81 | + }, | ||
| 82 | + created() { | ||
| 83 | + this.getList(); | ||
| 84 | + }, | ||
| 85 | + methods: { | ||
| 86 | + /** 查询登录日志列表 */ | ||
| 87 | + getList() { | ||
| 88 | + this.loading = true; | ||
| 89 | + list(this.queryParams).then(response => { | ||
| 90 | + this.list = response.data.list; | ||
| 91 | + this.total = response.data.total; | ||
| 92 | + this.loading = false; | ||
| 93 | + }); | ||
| 94 | + }, | ||
| 95 | + /** 搜索按钮操作 */ | ||
| 96 | + handleQuery() { | ||
| 97 | + this.pageNo = 1; | ||
| 98 | + this.getList(); | ||
| 99 | + }, | ||
| 100 | + /** 重置按钮操作 */ | ||
| 101 | + resetQuery() { | ||
| 102 | + this.resetForm("queryForm"); | ||
| 103 | + this.handleQuery(); | ||
| 104 | + }, | ||
| 105 | + /** 强退按钮操作 */ | ||
| 106 | + handleForceLogout(row) { | ||
| 107 | + this.$confirm('是否确认强退名称为"' + row.username + '"的数据项?', "警告", { | ||
| 108 | + confirmButtonText: "确定", | ||
| 109 | + cancelButtonText: "取消", | ||
| 110 | + type: "warning" | ||
| 111 | + }).then(function() { | ||
| 112 | + return forceLogout(row.id); | ||
| 113 | + }).then(() => { | ||
| 114 | + this.getList(); | ||
| 115 | + this.msgSuccess("强退成功"); | ||
| 116 | + }) | ||
| 117 | + } | ||
| 118 | + } | ||
| 119 | +}; | ||
| 120 | +</script> | ||
| 121 | + |
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/SysUserSessionController.java
| @@ -4,8 +4,14 @@ import cn.iocoder.dashboard.common.pojo.CommonResult; | @@ -4,8 +4,14 @@ import cn.iocoder.dashboard.common.pojo.CommonResult; | ||
| 4 | import cn.iocoder.dashboard.common.pojo.PageResult; | 4 | import cn.iocoder.dashboard.common.pojo.PageResult; |
| 5 | import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageItemRespVO; | 5 | import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageItemRespVO; |
| 6 | import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO; | 6 | import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO; |
| 7 | +import cn.iocoder.dashboard.modules.system.convert.auth.SysUserSessionConvert; | ||
| 7 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO; | 8 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO; |
| 9 | +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysDeptDO; | ||
| 10 | +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; | ||
| 8 | import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService; | 11 | import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService; |
| 12 | +import cn.iocoder.dashboard.modules.system.service.dept.SysDeptService; | ||
| 13 | +import cn.iocoder.dashboard.modules.system.service.user.SysUserService; | ||
| 14 | +import cn.iocoder.dashboard.util.collection.MapUtils; | ||
| 9 | import io.swagger.annotations.Api; | 15 | import io.swagger.annotations.Api; |
| 10 | import io.swagger.annotations.ApiImplicitParam; | 16 | import io.swagger.annotations.ApiImplicitParam; |
| 11 | import io.swagger.annotations.ApiOperation; | 17 | import io.swagger.annotations.ApiOperation; |
| @@ -14,26 +20,50 @@ import org.springframework.validation.annotation.Validated; | @@ -14,26 +20,50 @@ import org.springframework.validation.annotation.Validated; | ||
| 14 | import org.springframework.web.bind.annotation.*; | 20 | import org.springframework.web.bind.annotation.*; |
| 15 | 21 | ||
| 16 | import javax.annotation.Resource; | 22 | import javax.annotation.Resource; |
| 23 | +import java.util.ArrayList; | ||
| 24 | +import java.util.List; | ||
| 25 | +import java.util.Map; | ||
| 17 | 26 | ||
| 18 | import static cn.iocoder.dashboard.common.pojo.CommonResult.success; | 27 | import static cn.iocoder.dashboard.common.pojo.CommonResult.success; |
| 28 | +import static cn.iocoder.dashboard.util.collection.CollectionUtils.convertList; | ||
| 19 | 29 | ||
| 20 | @Api("用户 Session API") | 30 | @Api("用户 Session API") |
| 21 | @RestController | 31 | @RestController |
| 22 | -@RequestMapping("/user-session") | 32 | +@RequestMapping("/system/user-session") |
| 23 | public class SysUserSessionController { | 33 | public class SysUserSessionController { |
| 24 | 34 | ||
| 25 | @Resource | 35 | @Resource |
| 26 | private SysUserSessionService userSessionService; | 36 | private SysUserSessionService userSessionService; |
| 37 | + @Resource | ||
| 38 | + private SysUserService userService; | ||
| 39 | + @Resource | ||
| 40 | + private SysDeptService deptService; | ||
| 27 | 41 | ||
| 28 | @ApiOperation("获得 Session 分页列表") | 42 | @ApiOperation("获得 Session 分页列表") |
| 29 | @PreAuthorize("@ss.hasPermission('system:user-session:page')") | 43 | @PreAuthorize("@ss.hasPermission('system:user-session:page')") |
| 30 | @GetMapping("/page") | 44 | @GetMapping("/page") |
| 31 | public CommonResult<PageResult<SysUserSessionPageItemRespVO>> getUserSessionPage(@Validated SysUserSessionPageReqVO reqVO) { | 45 | public CommonResult<PageResult<SysUserSessionPageItemRespVO>> getUserSessionPage(@Validated SysUserSessionPageReqVO reqVO) { |
| 32 | // 获得 Session 分页 | 46 | // 获得 Session 分页 |
| 33 | - PageResult<SysUserSessionDO> sessionPage = userSessionService.getUserSessionPage(reqVO); | 47 | + PageResult<SysUserSessionDO> pageResult = userSessionService.getUserSessionPage(reqVO); |
| 34 | 48 | ||
| 35 | - // | ||
| 36 | - return null; | 49 | + // 获得拼接需要的数据 |
| 50 | + Map<Long, SysUserDO> userMap = userService.getUserMap( | ||
| 51 | + convertList(pageResult.getList(), SysUserSessionDO::getUserId)); | ||
| 52 | + Map<Long, SysDeptDO> deptMap = deptService.getDeptMap( | ||
| 53 | + convertList(userMap.values(), SysUserDO::getDeptId)); | ||
| 54 | + // 拼接结果返回 | ||
| 55 | + List<SysUserSessionPageItemRespVO> sessionList = new ArrayList<>(pageResult.getList().size()); | ||
| 56 | + pageResult.getList().forEach(session -> { | ||
| 57 | + SysUserSessionPageItemRespVO respVO = SysUserSessionConvert.INSTANCE.convert(session); | ||
| 58 | + sessionList.add(respVO); | ||
| 59 | + // 设置用户账号 | ||
| 60 | + MapUtils.findAndThen(userMap, session.getUserId(), user -> { | ||
| 61 | + respVO.setUsername(user.getUsername()); | ||
| 62 | + // 设置用户部门 | ||
| 63 | + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> respVO.setDeptName(dept.getName())); | ||
| 64 | + }); | ||
| 65 | + }); | ||
| 66 | + return success(new PageResult<>(sessionList, pageResult.getTotal())); | ||
| 37 | } | 67 | } |
| 38 | 68 | ||
| 39 | @ApiOperation("删除 Session") | 69 | @ApiOperation("删除 Session") |
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/session/SysUserSessionPageItemRespVO.java
| @@ -8,6 +8,8 @@ import lombok.Data; | @@ -8,6 +8,8 @@ import lombok.Data; | ||
| 8 | import lombok.EqualsAndHashCode; | 8 | import lombok.EqualsAndHashCode; |
| 9 | import lombok.NoArgsConstructor; | 9 | import lombok.NoArgsConstructor; |
| 10 | 10 | ||
| 11 | +import java.util.Date; | ||
| 12 | + | ||
| 11 | @ApiModel(value = "用户在线 Session Response VO", description = "相比用户基本信息来说,会多部门、用户账号等信息") | 13 | @ApiModel(value = "用户在线 Session Response VO", description = "相比用户基本信息来说,会多部门、用户账号等信息") |
| 12 | @Data | 14 | @Data |
| 13 | @NoArgsConstructor | 15 | @NoArgsConstructor |
| @@ -25,7 +27,7 @@ public class SysUserSessionPageItemRespVO extends PageParam { | @@ -25,7 +27,7 @@ public class SysUserSessionPageItemRespVO extends PageParam { | ||
| 25 | private String userAgent; | 27 | private String userAgent; |
| 26 | 28 | ||
| 27 | @ApiModelProperty(value = "登陆时间", required = true) | 29 | @ApiModelProperty(value = "登陆时间", required = true) |
| 28 | - private String createTime; | 30 | + private Date createTime; |
| 29 | 31 | ||
| 30 | @ApiModelProperty(value = "用户账号", required = true, example = "yudao") | 32 | @ApiModelProperty(value = "用户账号", required = true, example = "yudao") |
| 31 | private String username; | 33 | private String username; |
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/session/SysUserSessionPageReqVO.java
| @@ -14,7 +14,6 @@ import javax.validation.constraints.NotEmpty; | @@ -14,7 +14,6 @@ import javax.validation.constraints.NotEmpty; | ||
| 14 | public class SysUserSessionPageReqVO extends PageParam { | 14 | public class SysUserSessionPageReqVO extends PageParam { |
| 15 | 15 | ||
| 16 | @ApiModelProperty(value = "用户 IP", example = "127.0.0.1", notes = "模糊匹配") | 16 | @ApiModelProperty(value = "用户 IP", example = "127.0.0.1", notes = "模糊匹配") |
| 17 | - @NotEmpty(message = "用户 IP 不能为空") | ||
| 18 | private String userIp; | 17 | private String userIp; |
| 19 | 18 | ||
| 20 | @ApiModelProperty(value = "用户账号", example = "yudao", notes = "模糊匹配") | 19 | @ApiModelProperty(value = "用户账号", example = "yudao", notes = "模糊匹配") |
src/main/java/cn/iocoder/dashboard/modules/system/convert/auth/SysUserSessionConvert.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.convert.auth; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageItemRespVO; | ||
| 4 | +import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserPageItemRespVO; | ||
| 5 | +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO; | ||
| 6 | +import org.mapstruct.Mapper; | ||
| 7 | +import org.mapstruct.factory.Mappers; | ||
| 8 | + | ||
| 9 | +@Mapper | ||
| 10 | +public interface SysUserSessionConvert { | ||
| 11 | + | ||
| 12 | + SysUserSessionConvert INSTANCE = Mappers.getMapper(SysUserSessionConvert.class); | ||
| 13 | + | ||
| 14 | + SysUserSessionPageItemRespVO convert(SysUserSessionDO session); | ||
| 15 | + | ||
| 16 | +} |
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/auth/SysUserSessionMapper.java
| 1 | package cn.iocoder.dashboard.modules.system.dal.mysql.dao.auth; | 1 | package cn.iocoder.dashboard.modules.system.dal.mysql.dao.auth; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.dashboard.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; | ||
| 5 | +import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX; | ||
| 6 | +import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO; | ||
| 3 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO; | 7 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO; |
| 4 | -import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 5 | import org.apache.ibatis.annotations.Mapper; | 8 | import org.apache.ibatis.annotations.Mapper; |
| 6 | 9 | ||
| 10 | +import java.util.Collection; | ||
| 11 | + | ||
| 7 | @Mapper | 12 | @Mapper |
| 8 | -public interface SysUserSessionMapper extends BaseMapper<SysUserSessionDO> { | 13 | +public interface SysUserSessionMapper extends BaseMapperX<SysUserSessionDO> { |
| 14 | + | ||
| 15 | + default PageResult<SysUserSessionDO> selectPage(SysUserSessionPageReqVO reqVO, Collection<Long> userIds) { | ||
| 16 | + return selectPage(reqVO, new QueryWrapperX<SysUserSessionDO>() | ||
| 17 | + .inIfPresent("user_id", userIds) | ||
| 18 | + .likeIfPresent("user_ip", reqVO.getUserIp())); | ||
| 19 | + } | ||
| 20 | + | ||
| 9 | } | 21 | } |
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/user/SysUserMapper.java
| @@ -48,5 +48,9 @@ public interface SysUserMapper extends BaseMapperX<SysUserDO> { | @@ -48,5 +48,9 @@ public interface SysUserMapper extends BaseMapperX<SysUserDO> { | ||
| 48 | return selectList(new QueryWrapperX<SysUserDO>().like("nickname", nickname)); | 48 | return selectList(new QueryWrapperX<SysUserDO>().like("nickname", nickname)); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | + default List<SysUserDO> selectListByUsername(String username) { | ||
| 52 | + return selectList(new QueryWrapperX<SysUserDO>().like("username", username)); | ||
| 53 | + } | ||
| 54 | + | ||
| 51 | } | 55 | } |
| 52 | 56 |
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; | @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth; | ||
| 3 | import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; | 3 | import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; |
| 4 | import cn.iocoder.dashboard.framework.security.core.LoginUser; | 4 | import cn.iocoder.dashboard.framework.security.core.LoginUser; |
| 5 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; | 5 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; |
| 6 | +import com.baomidou.mybatisplus.annotation.IdType; | ||
| 6 | import com.baomidou.mybatisplus.annotation.TableId; | 7 | import com.baomidou.mybatisplus.annotation.TableId; |
| 7 | import com.baomidou.mybatisplus.annotation.TableName; | 8 | import com.baomidou.mybatisplus.annotation.TableName; |
| 8 | import lombok.Builder; | 9 | import lombok.Builder; |
| @@ -27,7 +28,7 @@ public class SysUserSessionDO extends BaseDO { | @@ -27,7 +28,7 @@ public class SysUserSessionDO extends BaseDO { | ||
| 27 | /** | 28 | /** |
| 28 | * 会话编号, 即 sessionId | 29 | * 会话编号, 即 sessionId |
| 29 | */ | 30 | */ |
| 30 | - @TableId | 31 | + @TableId(type = IdType.INPUT) |
| 31 | private String id; | 32 | private String id; |
| 32 | /** | 33 | /** |
| 33 | * 用户编号 | 34 | * 用户编号 |
src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/dao/auth/SysLoginUserRedisDAO.java
| @@ -30,8 +30,8 @@ public class SysLoginUserRedisDAO { | @@ -30,8 +30,8 @@ public class SysLoginUserRedisDAO { | ||
| 30 | stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(loginUser), LOGIN_USER.getTimeout()); | 30 | stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(loginUser), LOGIN_USER.getTimeout()); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | - public void delete(String accessToken) { | ||
| 34 | - String redisKey = formatKey(accessToken); | 33 | + public void delete(String sessionId) { |
| 34 | + String redisKey = formatKey(sessionId); | ||
| 35 | stringRedisTemplate.delete(redisKey); | 35 | stringRedisTemplate.delete(redisKey); |
| 36 | } | 36 | } |
| 37 | 37 |
src/main/java/cn/iocoder/dashboard/modules/system/job/package-info.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.job; |
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysUserSessionServiceImpl.java
| 1 | package cn.iocoder.dashboard.modules.system.service.auth.impl; | 1 | package cn.iocoder.dashboard.modules.system.service.auth.impl; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.hutool.core.util.IdUtil; | 4 | import cn.hutool.core.util.IdUtil; |
| 5 | +import cn.hutool.core.util.StrUtil; | ||
| 4 | import cn.iocoder.dashboard.common.pojo.PageResult; | 6 | import cn.iocoder.dashboard.common.pojo.PageResult; |
| 5 | import cn.iocoder.dashboard.framework.security.config.SecurityProperties; | 7 | import cn.iocoder.dashboard.framework.security.config.SecurityProperties; |
| 6 | import cn.iocoder.dashboard.framework.security.core.LoginUser; | 8 | import cn.iocoder.dashboard.framework.security.core.LoginUser; |
| 7 | import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO; | 9 | import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO; |
| 8 | import cn.iocoder.dashboard.modules.system.dal.mysql.dao.auth.SysUserSessionMapper; | 10 | import cn.iocoder.dashboard.modules.system.dal.mysql.dao.auth.SysUserSessionMapper; |
| 9 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO; | 11 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO; |
| 12 | +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; | ||
| 10 | import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO; | 13 | import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO; |
| 11 | import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService; | 14 | import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService; |
| 15 | +import cn.iocoder.dashboard.modules.system.service.user.SysUserService; | ||
| 12 | import org.springframework.stereotype.Service; | 16 | import org.springframework.stereotype.Service; |
| 13 | 17 | ||
| 14 | import javax.annotation.Resource; | 18 | import javax.annotation.Resource; |
| 19 | +import java.util.Collection; | ||
| 15 | import java.util.Date; | 20 | import java.util.Date; |
| 16 | 21 | ||
| 22 | +import static cn.iocoder.dashboard.util.collection.CollectionUtils.convertSet; | ||
| 23 | + | ||
| 17 | /** | 24 | /** |
| 18 | * 在线用户 Session Service 实现类 | 25 | * 在线用户 Session Service 实现类 |
| 19 | * | 26 | * |
| @@ -27,10 +34,12 @@ public class SysUserSessionServiceImpl implements SysUserSessionService { | @@ -27,10 +34,12 @@ public class SysUserSessionServiceImpl implements SysUserSessionService { | ||
| 27 | 34 | ||
| 28 | @Resource | 35 | @Resource |
| 29 | private SysLoginUserRedisDAO loginUserRedisDAO; | 36 | private SysLoginUserRedisDAO loginUserRedisDAO; |
| 30 | - | ||
| 31 | @Resource | 37 | @Resource |
| 32 | private SysUserSessionMapper userSessionMapper; | 38 | private SysUserSessionMapper userSessionMapper; |
| 33 | 39 | ||
| 40 | + @Resource | ||
| 41 | + private SysUserService userService; | ||
| 42 | + | ||
| 34 | @Override | 43 | @Override |
| 35 | public String createUserSession(LoginUser loginUser, String userIp, String userAgent) { | 44 | public String createUserSession(LoginUser loginUser, String userIp, String userAgent) { |
| 36 | // 生成 Session 编号 | 45 | // 生成 Session 编号 |
| @@ -39,8 +48,8 @@ public class SysUserSessionServiceImpl implements SysUserSessionService { | @@ -39,8 +48,8 @@ public class SysUserSessionServiceImpl implements SysUserSessionService { | ||
| 39 | loginUser.setUpdateTime(new Date()); | 48 | loginUser.setUpdateTime(new Date()); |
| 40 | loginUserRedisDAO.set(sessionId, loginUser); | 49 | loginUserRedisDAO.set(sessionId, loginUser); |
| 41 | // 写入 DB 中 | 50 | // 写入 DB 中 |
| 42 | - SysUserSessionDO userSession = SysUserSessionDO.builder().userId(loginUser.getId()) | ||
| 43 | - .userIp(userIp).userAgent(userAgent).build(); | 51 | + SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId) |
| 52 | + .userId(loginUser.getId()).userIp(userIp).userAgent(userAgent).build(); | ||
| 44 | userSessionMapper.insert(userSession); | 53 | userSessionMapper.insert(userSession); |
| 45 | // 返回 Session 编号 | 54 | // 返回 Session 编号 |
| 46 | return sessionId; | 55 | return sessionId; |
| @@ -59,7 +68,10 @@ public class SysUserSessionServiceImpl implements SysUserSessionService { | @@ -59,7 +68,10 @@ public class SysUserSessionServiceImpl implements SysUserSessionService { | ||
| 59 | 68 | ||
| 60 | @Override | 69 | @Override |
| 61 | public void deleteUserSession(String sessionId) { | 70 | public void deleteUserSession(String sessionId) { |
| 62 | - | 71 | + // 删除 Redis 缓存 |
| 72 | + loginUserRedisDAO.delete(sessionId); | ||
| 73 | + // 删除 DB 记录 | ||
| 74 | + userSessionMapper.deleteById(sessionId); | ||
| 63 | } | 75 | } |
| 64 | 76 | ||
| 65 | @Override | 77 | @Override |
| @@ -74,7 +86,15 @@ public class SysUserSessionServiceImpl implements SysUserSessionService { | @@ -74,7 +86,15 @@ public class SysUserSessionServiceImpl implements SysUserSessionService { | ||
| 74 | 86 | ||
| 75 | @Override | 87 | @Override |
| 76 | public PageResult<SysUserSessionDO> getUserSessionPage(SysUserSessionPageReqVO reqVO) { | 88 | public PageResult<SysUserSessionDO> getUserSessionPage(SysUserSessionPageReqVO reqVO) { |
| 77 | - return null; | 89 | + // 处理基于用户昵称的查询 |
| 90 | + Collection<Long> userIds = null; | ||
| 91 | + if (StrUtil.isNotEmpty(reqVO.getUsername())) { | ||
| 92 | + userIds = convertSet(userService.listUsersByUsername(reqVO.getUsername()), SysUserDO::getId); | ||
| 93 | + if (CollUtil.isEmpty(userIds)) { | ||
| 94 | + return PageResult.empty(); | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | + return userSessionMapper.selectPage(reqVO, userIds); | ||
| 78 | } | 98 | } |
| 79 | 99 | ||
| 80 | /** | 100 | /** |
src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserService.java
| @@ -80,6 +80,14 @@ public interface SysUserService { | @@ -80,6 +80,14 @@ public interface SysUserService { | ||
| 80 | List<SysUserDO> listUsersByNickname(String nickname); | 80 | List<SysUserDO> listUsersByNickname(String nickname); |
| 81 | 81 | ||
| 82 | /** | 82 | /** |
| 83 | + * 获得用户列表,基于用户账号模糊匹配 | ||
| 84 | + * | ||
| 85 | + * @param username 用户账号 | ||
| 86 | + * @return 用户列表 | ||
| 87 | + */ | ||
| 88 | + List<SysUserDO> listUsersByUsername(String username); | ||
| 89 | + | ||
| 90 | + /** | ||
| 83 | * 创建用户 | 91 | * 创建用户 |
| 84 | * | 92 | * |
| 85 | * @param reqVO 用户信息 | 93 | * @param reqVO 用户信息 |
src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImpl.java
| @@ -92,6 +92,11 @@ public class SysUserServiceImpl implements SysUserService { | @@ -92,6 +92,11 @@ public class SysUserServiceImpl implements SysUserService { | ||
| 92 | return userMapper.selectListByNickname(nickname); | 92 | return userMapper.selectListByNickname(nickname); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | + @Override | ||
| 96 | + public List<SysUserDO> listUsersByUsername(String username) { | ||
| 97 | + return userMapper.selectListByUsername(username); | ||
| 98 | + } | ||
| 99 | + | ||
| 95 | /** | 100 | /** |
| 96 | * 获得部门条件:查询指定部门的子部门编号们,包括自身 | 101 | * 获得部门条件:查询指定部门的子部门编号们,包括自身 |
| 97 | * | 102 | * |
src/main/java/cn/iocoder/dashboard/util/collection/CollectionUtils.java
| @@ -26,35 +26,35 @@ public class CollectionUtils { | @@ -26,35 +26,35 @@ public class CollectionUtils { | ||
| 26 | return from.stream().filter(predicate).collect(Collectors.toList()); | 26 | return from.stream().filter(predicate).collect(Collectors.toList()); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | - public static <T, U> List<U> convertList(List<T> from, Function<T, U> func) { | 29 | + public static <T, U> List<U> convertList(Collection<T> from, Function<T, U> func) { |
| 30 | if (CollUtil.isEmpty(from)) { | 30 | if (CollUtil.isEmpty(from)) { |
| 31 | return new ArrayList<>(); | 31 | return new ArrayList<>(); |
| 32 | } | 32 | } |
| 33 | return from.stream().map(func).collect(Collectors.toList()); | 33 | return from.stream().map(func).collect(Collectors.toList()); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | - public static <T, U> Set<U> convertSet(List<T> from, Function<T, U> func) { | 36 | + public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func) { |
| 37 | if (CollUtil.isEmpty(from)) { | 37 | if (CollUtil.isEmpty(from)) { |
| 38 | return new HashSet<>(); | 38 | return new HashSet<>(); |
| 39 | } | 39 | } |
| 40 | return from.stream().map(func).collect(Collectors.toSet()); | 40 | return from.stream().map(func).collect(Collectors.toSet()); |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | - public static <T, K> Map<K, T> convertMap(List<T> from, Function<T, K> keyFunc) { | 43 | + public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc) { |
| 44 | if (CollUtil.isEmpty(from)) { | 44 | if (CollUtil.isEmpty(from)) { |
| 45 | return new HashMap<>(); | 45 | return new HashMap<>(); |
| 46 | } | 46 | } |
| 47 | return from.stream().collect(Collectors.toMap(keyFunc, item -> item)); | 47 | return from.stream().collect(Collectors.toMap(keyFunc, item -> item)); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | - public static <T, K, V> Map<K, V> convertMap(List<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) { | 50 | + public static <T, K, V> Map<K, V> convertMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) { |
| 51 | if (CollUtil.isEmpty(from)) { | 51 | if (CollUtil.isEmpty(from)) { |
| 52 | return new HashMap<>(); | 52 | return new HashMap<>(); |
| 53 | } | 53 | } |
| 54 | return from.stream().collect(Collectors.toMap(keyFunc, valueFunc)); | 54 | return from.stream().collect(Collectors.toMap(keyFunc, valueFunc)); |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | - public static <T, K> Map<K, List<T>> convertMultiMap(List<T> from, Function<T, K> keyFunc) { | 57 | + public static <T, K> Map<K, List<T>> convertMultiMap(Collection<T> from, Function<T, K> keyFunc) { |
| 58 | if (CollUtil.isEmpty(from)) { | 58 | if (CollUtil.isEmpty(from)) { |
| 59 | return new HashMap<>(); | 59 | return new HashMap<>(); |
| 60 | } | 60 | } |
| @@ -62,7 +62,7 @@ public class CollectionUtils { | @@ -62,7 +62,7 @@ public class CollectionUtils { | ||
| 62 | Collectors.mapping(t -> t, Collectors.toList()))); | 62 | Collectors.mapping(t -> t, Collectors.toList()))); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | - public static <T, K, V> Map<K, List<V>> convertMultiMap(List<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) { | 65 | + public static <T, K, V> Map<K, List<V>> convertMultiMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) { |
| 66 | if (CollUtil.isEmpty(from)) { | 66 | if (CollUtil.isEmpty(from)) { |
| 67 | return new HashMap<>(); | 67 | return new HashMap<>(); |
| 68 | } | 68 | } |
| @@ -71,7 +71,7 @@ public class CollectionUtils { | @@ -71,7 +71,7 @@ public class CollectionUtils { | ||
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | // 暂时没想好名字,先以 2 结尾噶 | 73 | // 暂时没想好名字,先以 2 结尾噶 |
| 74 | - public static <T, K, V> Map<K, Set<V>> convertMultiMap2(List<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) { | 74 | + public static <T, K, V> Map<K, Set<V>> convertMultiMap2(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) { |
| 75 | if (CollUtil.isEmpty(from)) { | 75 | if (CollUtil.isEmpty(from)) { |
| 76 | return new HashMap<>(); | 76 | return new HashMap<>(); |
| 77 | } | 77 | } |