ruoyi后台管理系统分析
Posted zhzjava11
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ruoyi后台管理系统分析相关的知识,希望对你有一定的参考价值。
二、framework包
--aspectj包
DataScopeAspect.java
package com.ruoyi.framework.aspectj; import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import com.ruoyi.common.annotation.DataScope; import com.ruoyi.common.base.BaseEntity; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.util.ShiroUtils; import com.ruoyi.system.domain.SysRole; import com.ruoyi.system.domain.SysUser; /** * 数据过滤处理 * * @author ruoyi */ @Aspect @Component public class DataScopeAspect { /** * 全部数据权限 */ public static final String DATA_SCOPE_ALL = "1"; /** * 自定数据权限 */ public static final String DATA_SCOPE_CUSTOM = "2"; /** * 数据权限过滤关键字 */ public static final String DATA_SCOPE = "dataScope"; // 配置织入点 @Pointcut("@annotation(com.ruoyi.common.annotation.DataScope)") public void dataScopePointCut() { } @Before("dataScopePointCut()") public void doBefore(JoinPoint point) throws Throwable { handleDataScope(point); } protected void handleDataScope(final JoinPoint joinPoint) { // 获得注解 DataScope controllerDataScope = getAnnotationLog(joinPoint); if (controllerDataScope == null) { return; } // 获取当前的用户 SysUser currentUser = ShiroUtils.getUser(); if (currentUser != null) { // 如果是超级管理员,则不过滤数据 if (!currentUser.isAdmin()) { dataScopeFilter(joinPoint, currentUser, controllerDataScope.tableAlias()); } } } /** * 数据范围过滤 * * @param da 部门表别名 * @return 标准连接条件对象 */ public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String alias) { StringBuilder sqlString = new StringBuilder(); for (SysRole role : user.getRoles()) { String dataScope = role.getDataScope(); if (DATA_SCOPE_ALL.equals(dataScope)) { sqlString = new StringBuilder(); break; } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) { sqlString.append(StringUtils.format( " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", alias, role.getRoleId())); } } if (StringUtils.isNotBlank(sqlString.toString())) { BaseEntity baseEntity = (BaseEntity) joinPoint.getArgs()[0]; baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")"); } } /** * 是否存在注解,如果存在就获取 */ private DataScope getAnnotationLog(JoinPoint joinPoint) { Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); if (method != null) { return method.getAnnotation(DataScope.class); } return null; } }
DataSourceAspect.java
package com.ruoyi.framework.aspectj; import java.lang.reflect.Method; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import com.ruoyi.common.annotation.DataSource; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.datasource.DynamicDataSourceContextHolder; /** * 多数据源处理 * * @author ruoyi */ @Aspect @Order(1) @Component public class DataSourceAspect { protected Logger logger = LoggerFactory.getLogger(getClass()); @Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)") public void dsPointCut() { } @Around("dsPointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); DataSource dataSource = method.getAnnotation(DataSource.class); if (StringUtils.isNotNull(dataSource)) { DynamicDataSourceContextHolder.setDateSoureType(dataSource.value().name()); } try { return point.proceed(); } finally { // 销毁数据源 在执行方法之后 DynamicDataSourceContextHolder.clearDateSoureType(); } } }
LogAspect.java
package com.ruoyi.framework.aspectj; import java.lang.reflect.Method; import java.util.Map; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.enums.BusinessStatus; import com.ruoyi.common.json.JSON; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.manager.AsyncManager; import com.ruoyi.framework.manager.factory.AsyncFactory; import com.ruoyi.framework.util.ServletUtils; import com.ruoyi.framework.util.ShiroUtils; import com.ruoyi.system.domain.SysOperLog; import com.ruoyi.system.domain.SysUser; /** * 操作日志记录处理 * * @author ruoyi */ @Aspect @Component public class LogAspect { private static final Logger log = LoggerFactory.getLogger(LogAspect.class); // 配置织入点 @Pointcut("@annotation(com.ruoyi.common.annotation.Log)") public void logPointCut() { } /** * 前置通知 用于拦截操作 * * @param joinPoint 切点 */ @AfterReturning(pointcut = "logPointCut()") public void doBefore(JoinPoint joinPoint) { handleLog(joinPoint, null); } /** * 拦截异常操作 * * @param joinPoint * @param e */ @AfterThrowing(value = "logPointCut()", throwing = "e") public void doAfter(JoinPoint joinPoint, Exception e) { handleLog(joinPoint, e); } protected void handleLog(final JoinPoint joinPoint, final Exception e) { try { // 获得注解 Log controllerLog = getAnnotationLog(joinPoint); if (controllerLog == null) { return; } // 获取当前的用户 SysUser currentUser = ShiroUtils.getUser(); // *========数据库日志=========*// SysOperLog operLog = new SysOperLog(); operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); // 请求的地址 String ip = ShiroUtils.getIp(); operLog.setOperIp(ip); operLog.setOperUrl(ServletUtils.getRequest().getRequestURI()); if (currentUser != null) { operLog.setOperName(currentUser.getLoginName()); if (StringUtils.isNotNull(currentUser.getDept()) && StringUtils.isNotEmpty(currentUser.getDept().getDeptName())) { operLog.setDeptName(currentUser.getDept().getDeptName()); } } if (e != null) { operLog.setStatus(BusinessStatus.FAIL.ordinal()); operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); } // 设置方法名称 String className = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); operLog.setMethod(className + "." + methodName + "()"); // 处理设置注解上的参数 getControllerMethodDescription(controllerLog, operLog); // 保存数据库 AsyncManager.me().execute(AsyncFactory.recordOper(operLog)); } catch (Exception exp) { // 记录本地异常日志 log.error("==前置通知异常=="); log.error("异常信息:{}", exp.getMessage()); exp.printStackTrace(); } } /** * 获取注解中对方法的描述信息 用于Controller层注解 * * @param joinPoint 切点 * @return 方法描述 * @throws Exception */ public void getControllerMethodDescription(Log log, SysOperLog operLog) throws Exception { // 设置action动作 operLog.setBusinessType(log.businessType().ordinal()); // 设置标题 operLog.setTitle(log.title()); // 设置操作人类别 operLog.setOperatorType(log.operatorType().ordinal()); // 是否需要保存request,参数和值 if (log.isSaveRequestData()) { // 获取参数的信息,传入到数据库中。 setRequestValue(operLog); } } /** * 获取请求的参数,放到log中 * * @param operLog 操作日志 * @throws Exception 异常 */ private void setRequestValue(SysOperLog operLog) throws Exception { Map<String, String[]> map = ServletUtils.getRequest().getParameterMap(); String params = JSON.marshal(map); operLog.setOperParam(StringUtils.substring(params, 0, 255)); } /** * 是否存在注解,如果存在就获取 */ private Log getAnnotationLog(JoinPoint joinPoint) throws Exception { Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); if (method != null) { return method.getAnnotation(Log.class); } return null; } }
CaptchaConfig.java
package com.ruoyi.framework.config; import java.util.Properties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.google.code.kaptcha.impl.DefaultKaptcha; import com.google.code.kaptcha.util.Config; /** * 验证码配置 * * @author ruoyi */ @Configuration public class CaptchaConfig { @Bean(name = "captchaProducer") public DefaultKaptcha getKaptchaBean() { DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); Properties properties = new Properties(); properties.setProperty("kaptcha.border", "yes"); properties.setProperty("kaptcha.border.color", "105,179,90"); properties.setProperty("kaptcha.textproducer.font.color", "blue"); properties.setProperty("kaptcha.image.width", "160"); properties.setProperty("kaptcha.image.height", "60"); properties.setProperty("kaptcha.textproducer.font.size", "28"); properties.setProperty("kaptcha.session.key", "kaptchaCode"); properties.setProperty("kaptcha.textproducer.char.spac", "35"); properties.setProperty("kaptcha.textproducer.char.length", "5"); properties.setProperty("kaptcha.textproducer.font.names", "Arial,Courier"); properties.setProperty("kaptcha.noise.color", "white"); Config config = new Config(properties); defaultKaptcha.setConfig(config); return defaultKaptcha; } @Bean(name = "captchaProducerMath") public DefaultKaptcha getKaptchaBeanMath() { DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); Properties properties = new Properties(); properties.setProperty("kaptcha.border", "yes"); properties.setProperty("kaptcha.border.color", "105,179,90"); properties.setProperty("kaptcha.textproducer.font.color", "blue"); properties.setProperty("kaptcha.image.width", "160"); properties.setProperty("kaptcha.image.height", "60"); properties.setProperty("kaptcha.textproducer.font.size", "38"); properties.setProperty("kaptcha.session.key", "kaptchaCodeMath"); properties.setProperty("kaptcha.textproducer.impl", "com.ruoyi.framework.config.KaptchaTextCreator"); properties.setProperty("kaptcha.textproducer.char.spac", "5"); properties.setProperty("kaptcha.textproducer.char.length", "6"); properties.setProperty("kaptcha.textproducer.font.names", "Arial,Courier"); properties.setProperty("kaptcha.noise.color", "white"); properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise"); properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.ShadowGimpy"); Config config = new Config(properties); defaultKaptcha.setConfig(config); return defaultKaptcha; } }
DruidConfig.java
package com.ruoyi.framework.config; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import com.ruoyi.common.enums.DataSourceType; import com.ruoyi.framework.datasource.DynamicDataSource; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; /** * druid 配置多数据源 * * @author ruoyi */ @Configuration public class DruidConfig { @Bean @ConfigurationProperties("spring.datasource.druid.master") public DataSource masterDataSource() { return DruidDataSourceBuilder.create().build(); } @Bean @ConfigurationProperties("spring.datasource.druid.slave") @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") public DataSource slaveDataSource() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "dynamicDataSource") @Primary public DynamicDataSource dataSource(DataSource masterDataSource, DataSource slaveDataSource) { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource); targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource); return new DynamicDataSource(masterDataSource, targetDataSources); } }
package com.ruoyi.framework.config; import java.util.HashMap; import java.util.Map; import javax.servlet.DispatcherType; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.xss.XssFilter; /** * Filter配置 * * @author ruoyi */ @Configuration public class FilterConfig { @Value("${xss.enabled}") private String enabled; @Value("${xss.excludes}") private String excludes; @Value("${xss.urlPatterns}") private String urlPatterns; @SuppressWarnings({ "rawtypes", "unchecked" }) @Bean public FilterRegistrationBean xssFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setDispatcherTypes(DispatcherType.REQUEST); registration.setFilter(new XssFilter()); registration.addUrlPatterns(StringUtils.split(urlPatterns, ",")); registration.setName("xssFilter"); registration.setOrder(Integer.MAX_VALUE); Map<String, String> initParameters = new HashMap<String, String>(); initParameters.put("excludes", excludes); initParameters.put("enabled", enabled); registration.setInitParameters(initParameters); return registration; } }
GenConfig.java
package com.ruoyi.framework.config; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * 读取代码生成相关配置 * * @author ruoyi */ @Component @ConfigurationProperties(prefix = "gen") public class GenConfig { /** 作者 */ public static String author; /** 生成包路径 */ public static String packageName; /** 自动去除表前缀,默认是true */ public static String autoRemovePre; /** 表前缀(类名不会包含表前缀) */ public static String tablePrefix; public static String getAuthor() { return author; } public void setAuthor(String author) { GenConfig.author = author; } public static String getPackageName() { return packageName; } public void setPackageName(String packageName) { GenConfig.packageName = packageName; } public static String getAutoRemovePre() { return autoRemovePre; } public void setAutoRemovePre(String autoRemovePre) { GenConfig.autoRemovePre = autoRemovePre; } public static String getTablePrefix() { return tablePrefix; } public void setTablePrefix(String tablePrefix) { GenConfig.tablePrefix = tablePrefix; } }
I18nConfig.java
package com.ruoyi.framework.config; import java.util.Locale; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; import org.springframework.web.servlet.i18n.SessionLocaleResolver; /** * 资源文件配置加载 * * @author ruoyi */ @Configuration public class I18nConfig implements WebMvcConfigurer { @Bean public LocaleResolver localeResolver() { SessionLocaleResolver slr = new SessionLocaleResolver(); // 默认语言 slr.setDefaultLocale(Locale.SIMPLIFIED_CHINESE); return slr; } @Bean public LocaleChangeInterceptor localeChangeInterceptor() { LocaleChangeInterceptor lci = new LocaleChangeInterceptor(); // 参数名 lci.setParamName("lang"); return lci; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(localeChangeInterceptor()); } }
KaptchaTextCreator.java
package com.ruoyi.framework.config; import java.util.Random; import com.google.code.kaptcha.text.impl.DefaultTextCreator; /** * 验证码文本生成器 * * @author ruoyi */ public class KaptchaTextCreator extends DefaultTextCreator { private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(","); @Override public String getText() { Integer result = 0; Random random = new Random(); int x = random.nextInt(10); int y = random.nextInt(10); StringBuilder suChinese = new StringBuilder(); int randomoperands = (int) Math.round(Math.random() * 2); if (randomoperands == 0) { result = x * y; suChinese.append(CNUMBERS[x]); suChinese.append("*"); suChinese.append(CNUMBERS[y]); } else if (randomoperands == 1) { if (!(x == 0) && y % x == 0) { result = y / x; suChinese.append(CNUMBERS[y]); suChinese.append("/"); suChinese.append(CNUMBERS[x]); } else { result = x + y; suChinese.append(CNUMBERS[x]); suChinese.append("+"); suChinese.append(CNUMBERS[y]); } } else if (randomoperands == 2) { if (x >= y) { result = x - y; suChinese.append(CNUMBERS[x]); suChinese.append("-"); suChinese.append(CNUMBERS[y]); } else { result = y - x; suChinese.append(CNUMBERS[y]); suChinese.append("-"); suChinese.append(CNUMBERS[x]); } } else { result = x + y; suChinese.append(CNUMBERS[x]); suChinese.append("+"); suChinese.append(CNUMBERS[y]); } suChinese.append("[email protected]" + result); return suChinese.toString(); } }
ResourcesConfig.java
package com.ruoyi.framework.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.ruoyi.common.config.Global; /** * 通用配置 * * @author ruoyi */ @Configuration public class ResourcesConfig implements WebMvcConfigurer { /** * 首页地址 */ @Value("${shiro.user.indexUrl}") private String indexUrl; /** * 默认首页的设置,当输入域名是可以自动跳转到默认指定的网页 */ @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("forward:" + indexUrl); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { /** 文件上传路径 */ registry.addResourceHandler("/profile/**").addResourceLocations("file:" + Global.getProfile()); /** swagger配置 */ registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); } }
ShiroConfig.java
package com.ruoyi.framework.config; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.shiro.realm.UserRealm; import com.ruoyi.framework.shiro.session.OnlineSessionDAO; import com.ruoyi.framework.shiro.session.OnlineSessionFactory; import com.ruoyi.framework.shiro.web.filter.LogoutFilter; import com.ruoyi.framework.shiro.web.filter.captcha.CaptchaValidateFilter; import com.ruoyi.framework.shiro.web.filter.online.OnlineSessionFilter; import com.ruoyi.framework.shiro.web.filter.sync.SyncOnlineSessionFilter; import com.ruoyi.framework.shiro.web.session.OnlineWebSessionManager; import com.ruoyi.framework.shiro.web.session.SpringSessionValidationScheduler; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.codec.Base64; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; import java.util.LinkedHashMap; import java.util.Map; /** * 权限配置加载 * * @author ruoyi */ @Configuration public class ShiroConfig { public static final String PREMISSION_STRING = "perms["{0}"]"; // Session超时时间,单位为毫秒(默认30分钟) @Value("${shiro.session.expireTime}") private int expireTime; // 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟 @Value("${shiro.session.validationInterval}") private int validationInterval; // 验证码开关 @Value("${shiro.user.captchaEnabled}") private boolean captchaEnabled; // 验证码类型 @Value("${shiro.user.captchaType}") private String captchaType; // 设置Cookie的域名 @Value("${shiro.cookie.domain}") private String domain; // 设置cookie的有效访问路径 @Value("${shiro.cookie.path}") private String path; // 设置HttpOnly属性 @Value("${shiro.cookie.httpOnly}") private boolean httpOnly; // 设置Cookie的过期时间,秒为单位 @Value("${shiro.cookie.maxAge}") private int maxAge; // 登录地址 @Value("${shiro.user.loginUrl}") private String loginUrl; // 权限认证失败地址 @Value("${shiro.user.unauthorizedUrl}") private String unauthorizedUrl; /** * 缓存管理器 使用Ehcache实现 */ @Bean public EhCacheManager getEhCacheManager() { net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi"); EhCacheManager em = new EhCacheManager(); if (StringUtils.isNull(cacheManager)) { em.setCacheManagerConfigFile("classpath:ehcache/ehcache-shiro.xml"); return em; } else { em.setCacheManager(cacheManager); return em; } } /** * 自定义Realm */ @Bean public UserRealm userRealm(EhCacheManager cacheManager) { UserRealm userRealm = new UserRealm(); userRealm.setCacheManager(cacheManager); return userRealm; } /** * 自定义sessionDAO会话 */ @Bean public OnlineSessionDAO sessionDAO() { OnlineSessionDAO sessionDAO = new OnlineSessionDAO(); return sessionDAO; } /** * 自定义sessionFactory会话 */ @Bean public OnlineSessionFactory sessionFactory() { OnlineSessionFactory sessionFactory = new OnlineSessionFactory(); return sessionFactory; } /** * 自定义sessionFactory调度器 */ @Bean public SpringSessionValidationScheduler sessionValidationScheduler() { SpringSessionValidationScheduler sessionValidationScheduler = new SpringSessionValidationScheduler(); // 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟 sessionValidationScheduler.setSessionValidationInterval(validationInterval * 60 * 1000); // 设置会话验证调度器进行会话验证时的会话管理器 sessionValidationScheduler.setSessionManager(sessionValidationManager()); return sessionValidationScheduler; } /** * 会话管理器 */ @Bean public OnlineWebSessionManager sessionValidationManager() { OnlineWebSessionManager manager = new OnlineWebSessionManager(); // 加入缓存管理器 manager.setCacheManager(getEhCacheManager()); // 删除过期的session manager.setDeleteInvalidSessions(true); // 设置全局session超时时间 manager.setGlobalSessionTimeout(expireTime * 60 * 1000); // 去掉 JSESSIONID manager.setSessionIdUrlRewritingEnabled(false); // 是否定时检查session manager.setSessionValidationSchedulerEnabled(true); // 自定义SessionDao manager.setSessionDAO(sessionDAO()); // 自定义sessionFactory manager.setSessionFactory(sessionFactory()); return manager; } /** * 会话管理器 */ @Bean public OnlineWebSessionManager sessionManager() { OnlineWebSessionManager manager = new OnlineWebSessionManager(); // 加入缓存管理器 manager.setCacheManager(getEhCacheManager()); // 删除过期的session manager.setDeleteInvalidSessions(true); // 设置全局session超时时间 manager.setGlobalSessionTimeout(expireTime * 60 * 1000); // 去掉 JSESSIONID manager.setSessionIdUrlRewritingEnabled(false); // 定义要使用的无效的Session定时调度器 manager.setSessionValidationScheduler(sessionValidationScheduler()); // 是否定时检查session manager.setSessionValidationSchedulerEnabled(true); // 自定义SessionDao manager.setSessionDAO(sessionDAO()); // 自定义sessionFactory manager.setSessionFactory(sessionFactory()); return manager; } /** * 安全管理器 */ @Bean public SecurityManager securityManager(UserRealm userRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 设置realm. securityManager.setRealm(userRealm); // 记住我 securityManager.setRememberMeManager(rememberMeManager()); // 注入缓存管理器; securityManager.setCacheManager(getEhCacheManager()); // session管理器 securityManager.setSessionManager(sessionManager()); return securityManager; } /** * 退出过滤器 */ public LogoutFilter logoutFilter() { LogoutFilter logoutFilter = new LogoutFilter(); logoutFilter.setLoginUrl(loginUrl); return logoutFilter; } /** * Shiro过滤器配置 */ @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // Shiro的核心安全接口,这个属性是必须的 shiroFilterFactoryBean.setSecurityManager(securityManager); // 身份认证失败,则跳转到登录页面的配置 shiroFilterFactoryBean.setLoginUrl(loginUrl); // 权限认证失败,则跳转到指定页面 shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl); // Shiro连接约束配置,即过滤链的定义 LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); // 对静态资源设置匿名访问 filterChainDefinitionMap.put("/favicon.ico**", "anon"); // uflo工作流不拦截 filterChainDefinitionMap.put("/uflo/**", "anon"); filterChainDefinitionMap.put("/ruoyi.png**", "anon"); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/docs/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/ajax/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/ruoyi/**", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/captcha/captchaImage**", "anon"); // 退出 logout地址,shiro去清除session filterChainDefinitionMap.put("/logout", "logout"); // 不需要拦截的访问 filterChainDefinitionMap.put("/login", "anon,captchaValidate"); // 系统权限列表 // filterChainDefinitionMap.putAll(SpringUtils.getBean(IMenuService.class).selectPermsAll()); Map<String, Filter> filters = new LinkedHashMap<>(); filters.put("onlineSession", onlineSessionFilter()); filters.put("syncOnlineSession", syncOnlineSessionFilter()); filters.put("captchaValidate", captchaValidateFilter()); // 注销成功,则跳转到指定页面 filters.put("logout", logoutFilter()); shiroFilterFactoryBean.setFilters(filters); // 所有请求需要认证 filterChainDefinitionMap.put("/**", "user,onlineSession,syncOnlineSession"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } /** * 自定义在线用户处理过滤器 */ @Bean public OnlineSessionFilter onlineSessionFilter() { OnlineSessionFilter onlineSessionFilter = new OnlineSessionFilter(); onlineSessionFilter.setLoginUrl(loginUrl); return onlineSessionFilter; } /** * 自定义在线用户同步过滤器 */ @Bean public SyncOnlineSessionFilter syncOnlineSessionFilter() { SyncOnlineSessionFilter syncOnlineSessionFilter = new SyncOnlineSessionFilter(); return syncOnlineSessionFilter; } /** * 自定义验证码过滤器 */ @Bean public CaptchaValidateFilter captchaValidateFilter() { CaptchaValidateFilter captchaValidateFilter = new CaptchaValidateFilter(); captchaValidateFilter.setCaptchaEnabled(captchaEnabled); captchaValidateFilter.setCaptchaType(captchaType); return captchaValidateFilter; } /** * cookie 属性设置 */ public SimpleCookie rememberMeCookie() { SimpleCookie cookie = new SimpleCookie("rememberMe"); cookie.setDomain(domain); cookie.setPath(path); cookie.setHttpOnly(httpOnly); cookie.setMaxAge(maxAge * 24 * 60 * 60); return cookie; } /** * 记住我 */ public CookieRememberMeManager rememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); cookieRememberMeManager.setCipherKey(Base64.decode("fCq+/xW488hMTCD+cmJ3aQ==")); return cookieRememberMeManager; } /** * thymeleaf模板引擎和shiro框架的整合 */ @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } /** * 开启Shiro注解通知器 */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor( @Qualifier("securityManager") SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } }
-----datasource包
DynamicDataSource.java
package com.ruoyi.framework.datasource; import java.util.Map; import javax.sql.DataSource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * 动态数据源 * * @author ruoyi */ public class DynamicDataSource extends AbstractRoutingDataSource { public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) { super.setDefaultTargetDataSource(defaultTargetDataSource); super.setTargetDataSources(targetDataSources); super.afterPropertiesSet(); } @Override protected Object determineCurrentLookupKey() { return DynamicDataSourceContextHolder.getDateSoureType(); } }
DynamicDataSourceContextHolder.java
package com.ruoyi.framework.datasource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 数据源切换处理 * * @author ruoyi */ public class DynamicDataSourceContextHolder { public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class); /** * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本, * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 */ private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>(); /** * 设置数据源的变量 */ public static void setDateSoureType(String dsType) { log.info("切换到{}数据源", dsType); CONTEXT_HOLDER.set(dsType); } /** * 获得数据源的变量 */ public static String getDateSoureType() { return CONTEXT_HOLDER.get(); } /** * 清空数据源变量 */ public static void clearDateSoureType() { CONTEXT_HOLDER.remove(); } }
--manager包
-----factory包
AsyncFactory.java
package com.ruoyi.framework.manager.factory; import java.util.TimerTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.utils.AddressUtils; import com.ruoyi.framework.shiro.session.OnlineSession; import com.ruoyi.framework.util.LogUtils; import com.ruoyi.framework.util.ServletUtils; import com.ruoyi.framework.util.ShiroUtils; import com.ruoyi.framework.util.SpringUtils; import com.ruoyi.system.domain.SysLogininfor; import com.ruoyi.system.domain.SysOperLog; import com.ruoyi.system.domain.SysUserOnline; import com.ruoyi.system.service.ISysOperLogService; import com.ruoyi.system.service.impl.SysLogininforServiceImpl; import com.ruoyi.system.service.impl.SysUserOnlineServiceImpl; import eu.bitwalker.useragentutils.UserAgent; /** * 异步工厂(产生任务用) * * @author liuhulu * */ public class AsyncFactory { private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user"); /** * 同步session到数据库 * * @param session 在线用户会话 * @return 任务task */ public static TimerTask syncSessionToDb(final OnlineSession session) { return new TimerTask() { @Override public void run() { SysUserOnline online = new SysUserOnline(); online.setSessionId(String.valueOf(session.getId())); online.setDeptName(session.getDeptName()); online.setLoginName(session.getLoginName()); online.setStartTimestamp(session.getStartTimestamp()); online.setLastAccessTime(session.getLastAccessTime()); online.setExpireTime(session.getTimeout()); online.setIpaddr(session.getHost()); online.setLoginLocation(AddressUtils.getRealAddressByIP(session.getHost())); online.setBrowser(session.getBrowser()); online.setOs(session.getOs()); online.setStatus(session.getStatus()); SpringUtils.getBean(SysUserOnlineServiceImpl.class).saveOnline(online); } }; } /** * 操作日志记录 * * @param operLog 操作日志信息 * @return 任务task */ public static TimerTask recordOper(final SysOperLog operLog) { return new TimerTask() { @Override public void run() { // 远程查询操作地点 operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp())); SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog); } }; } /** * 记录登陆信息 * * @param username 用户名 * @param status 状态 * @param message 消息 * @param args 列表 * @return 任务task */ public static TimerTask recordLogininfor(final String username, final String status, final String message, final Object... args) { final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); final String ip = ShiroUtils.getIp(); return new TimerTask() { @Override public void run() { StringBuilder s = new StringBuilder(); s.append(LogUtils.getBlock(ip)); s.append(AddressUtils.getRealAddressByIP(ip)); s.append(LogUtils.getBlock(username)); s.append(LogUtils.getBlock(status)); s.append(LogUtils.getBlock(message)); // 打印信息到日志 sys_user_logger.info(s.toString(), args); // 获取客户端操作系统 String os = userAgent.getOperatingSystem().getName(); // 获取客户端浏览器 String browser = userAgent.getBrowser().getName(); // 封装对象 SysLogininfor logininfor = new SysLogininfor(); logininfor.setLoginName(username); logininfor.setIpaddr(ip); logininfor.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); logininfor.setBrowser(browser); logininfor.setOs(os); logininfor.setMsg(message); // 日志状态 if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status)) { logininfor.setStatus(Constants.SUCCESS); } else if (Constants.LOGIN_FAIL.equals(status)) { logininfor.setStatus(Constants.FAIL); } // 插入数据 SpringUtils.getBean(SysLogininforServiceImpl.class).insertLogininfor(logininfor); } }; } }
AsyncManager.java
package com.ruoyi.framework.manager; import java.util.TimerTask; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * 异步任务管理器 * * @author liuhulu */ public class AsyncManager { /** * 操作延迟10毫秒 */ private final int OPERATE_DELAY_TIME = 10; /** * 异步操作任务调度线程池 */ private ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5); /** * 单例模式 */ private static AsyncManager me = new AsyncManager(); public static AsyncManager me() { return me; } /** * 执行任务 * * @param 任务task */ public void execute(TimerTask task) { executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS); } }
以上是关于ruoyi后台管理系统分析的主要内容,如果未能解决你的问题,请参考以下文章