RuoYi-Vue-master/document/03-业务功能分析.md
Leo 6114f9eeb5 添加项目文档和配置
- 添加CLAUDE.md项目配置指南
- 添加document目录包含详细的架构分析文档
- 添加doc目录包含环境使用手册
- 添加bin目录包含构建和清理脚本
- 添加.github配置文件
2025-09-26 21:06:25 +08:00

39 KiB
Raw Blame History

RuoYi-Vue 业务功能分析报告

1. 业务功能概览

RuoYi-Vue 是一个功能完整的企业级后台管理系统框架提供了企业应用开发所需的基础功能模块。系统基于RBAC基于角色的访问控制权限模型构建了完整的用户管理、权限控制、系统监控等核心业务功能。

1.1 功能架构图

┌─────────────────────────────────────────────────────────────────┐
│                       RuoYi-Vue 功能架构                         │
└─────────────────────────────────────────────────────────────────┘
              ┌─────────────┐  ┌─────────────┐  ┌─────────────┐
              │  系统管理    │  │  系统监控    │  │  系统工具    │
              │             │  │             │  │             │
              │ • 用户管理   │  │ • 操作日志   │  │ • 表单构建   │
              │ • 角色管理   │  │ • 登录日志   │  │ • 代码生成   │
              │ • 菜单管理   │  │ • 在线用户   │  │ • 系统接口   │
              │ • 部门管理   │  │ • 定时任务   │  │             │
              │ • 岗位管理   │  │ • 数据监控   │  │             │
              │ • 字典管理   │  │ • 服务监控   │  │             │
              │ • 参数设置   │  │ • 缓存监控   │  │             │
              │ • 通知公告   │  │             │  │             │
              └─────────────┘  └─────────────┘  └─────────────┘
                                        │
                              ┌─────────────────┐
                              │    权限控制     │
                              │                │
                              │ • RBAC权限模型  │
                              │ • 数据权限控制  │
                              │ • 菜单权限控制  │
                              │ • 按钮权限控制  │
                              └─────────────────┘

1.2 核心业务价值

业务价值 具体体现 应用效果
权限管控 细粒度权限控制体系 数据安全,操作规范
效率提升 代码生成器等工具 开发效率提升80%
系统监控 全方位系统监控 运维效率显著提升
标准化 统一的开发规范 代码质量和维护性
可扩展 模块化设计架构 业务快速扩展

2. 系统管理模块分析

2.1 用户管理

功能特性

用户管理是系统的核心基础模块,提供了完整的用户生命周期管理功能。

核心功能清单:

  • 用户信息CRUD操作
  • 用户状态管理(启用/禁用)
  • 用户角色分配
  • 用户导入/导出
  • 密码重置和修改
  • 用户头像上传
  • 个人资料管理

业务流程分析

用户创建流程:

管理员登录 → 进入用户管理 → 点击新增用户 → 填写用户信息 → 选择所属部门 
    ↓
分配用户角色 → 设置用户状态 → 提交保存 → 系统验证数据 → 创建成功

权限验证机制:

@PreAuthorize("@ss.hasPermi('system:user:add')")
@Log(title = "用户管理", businessType = BusinessType.INSERT)
public AjaxResult add(@Validated @RequestBody SysUser user) {
    // 1. 验证用户名唯一性
    if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user.getUserName()))) {
        return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
    }
    // 2. 验证手机号唯一性  
    else if (StringUtils.isNotEmpty(user.getPhonenumber()) 
             && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) {
        return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
    }
    // 3. 验证邮箱唯一性
    else if (StringUtils.isNotEmpty(user.getEmail()) 
             && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) {
        return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
    }
    
    // 4. 设置创建者信息
    user.setCreateBy(getUsername());
    user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
    return toAjax(userService.insertUser(user));
}

数据模型设计

-- 用户表核心字段
CREATE TABLE `sys_user` (
  `user_id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `dept_id` bigint DEFAULT NULL COMMENT '部门ID',
  `user_name` varchar(30) NOT NULL COMMENT '用户账号',
  `nick_name` varchar(30) NOT NULL COMMENT '用户昵称', 
  `user_type` varchar(2) DEFAULT '00' COMMENT '用户类型00系统用户',
  `email` varchar(50) DEFAULT '' COMMENT '用户邮箱',
  `phonenumber` varchar(11) DEFAULT '' COMMENT '手机号码',
  `sex` char(1) DEFAULT '0' COMMENT '用户性别0男 1女 2未知',
  `avatar` varchar(100) DEFAULT '' COMMENT '头像地址',
  `password` varchar(100) DEFAULT '' COMMENT '密码',
  `status` char(1) DEFAULT '0' COMMENT '帐号状态0正常 1停用',
  `del_flag` char(1) DEFAULT '0' COMMENT '删除标志0代表存在 2代表删除',
  `login_ip` varchar(128) DEFAULT '' COMMENT '最后登录IP',
  `login_date` datetime DEFAULT NULL COMMENT '最后登录时间',
  -- 审计字段
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新者', 
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB COMMENT='用户信息表';

应用场景

场景 描述 使用频率
员工入职 HR创建新员工账号分配基础权限 中频
权限调整 根据岗位变动调整用户权限 高频
离职处理 禁用离职员工账号,保留数据 低频
批量导入 系统上线时批量导入用户数据 低频
个人信息 用户自主修改个人资料 中频

2.2 角色管理

功能特性

角色管理实现了RBAC权限模型中的角色概念是权限控制的核心枢纽。

核心功能清单:

  • 角色信息CRUD操作
  • 角色权限分配
  • 角色数据权限设置
  • 角色用户关联管理
  • 角色状态控制
  • 角色导出功能

权限分配机制

菜单权限分配:

// 前端权限树选择组件
<el-tree
  :data="menuOptions"
  show-checkbox
  ref="menu"
  node-key="id"
  :check-strictly="!form.menuCheckStrictly"
  empty-text="加载中,请稍候"
  :props="defaultProps">
</el-tree>

// 权限选择处理逻辑
getMenuTreeselect() {
  menuTreeselect().then(response => {
    this.menuOptions = response.data;
  });
},
// 根据角色ID查询菜单树结构
getRoleMenuTreeselect(roleId) {
  return roleMenuTreeselect(roleId).then(response => {
    this.menuOptions = response.menus;
    this.$refs.menu.setCheckedKeys(response.checkedKeys);
  });
}

数据权限控制:

/**
 * 数据权限范围
 * 1=全部数据权限
 * 2=自定数据权限  
 * 3=本部门数据权限
 * 4=本部门及以下数据权限
 * 5=仅本人数据权限
 */
@Component("ss")
public class PermissionService {
    
    @Autowired
    private TokenService tokenService;
    
    /**
     * 验证用户是否具备某权限
     */
    public boolean hasPermi(String permission) {
        if (StringUtils.isEmpty(permission)) {
            return false;
        }
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) {
            return false;
        }
        return hasPermissions(loginUser.getPermissions(), permission);
    }
}

数据权限实现

@Aspect
@Component
public class DataScopeAspect {
    
    @Before("@annotation(controllerDataScope)")
    public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable {
        clearDataScope(point);
        handleDataScope(point, controllerDataScope);
    }
    
    protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope) {
        // 获取当前的用户
        LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
        if (StringUtils.isNotNull(loginUser)) {
            SysUser currentUser = loginUser.getUser();
            // 如果是超级管理员,则不过滤数据
            if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) {
                dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), 
                              controllerDataScope.userAlias());
            }
        }
    }
    
    /**
     * 数据范围过滤
     */
    public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias) {
        StringBuilder sqlString = new StringBuilder();
        
        for (SysRole role : user.getRoles()) {
            String dataScope = role.getDataScope();
            if (DATA_SCOPE_ALL.equals(dataScope)) {
                sqlString = new StringBuilder();
                break;
            } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) {
                sqlString.append(StringUtils.format(
                    " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", 
                    deptAlias, role.getRoleId()));
            } else if (DATA_SCOPE_DEPT.equals(dataScope)) {
                sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
            } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) {
                sqlString.append(StringUtils.format(
                    " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
                    deptAlias, user.getDeptId(), user.getDeptId()));
            } else if (DATA_SCOPE_SELF.equals(dataScope)) {
                if (StringUtils.isNotBlank(userAlias)) {
                    sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
                } else {
                    sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
                }
            }
        }
        
        if (StringUtils.isNotBlank(sqlString.toString())) {
            Object params = joinPoint.getArgs()[0];
            if (StringUtils.isNotNull(params) && params instanceof BaseEntity) {
                BaseEntity baseEntity = (BaseEntity) params;
                baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
            }
        }
    }
}

2.3 菜单管理

功能特性

菜单管理负责系统的导航结构和权限控制的载体,支持多级菜单结构。

核心功能清单:

  • 树形菜单结构管理
  • 菜单类型区分(目录/菜单/按钮)
  • 菜单图标和路径配置
  • 菜单权限标识
  • 菜单状态控制
  • 菜单排序功能

菜单类型说明

菜单类型 说明 示例 权限控制
目录(M) 导航目录,不对应具体页面 系统管理 控制目录显示
菜单(C) 具体的功能页面 用户管理 控制页面访问
按钮(F) 页面内的操作按钮 新增、删除 控制按钮显示

动态路由生成

// 前端动态路由生成
import { constantRoutes } from '@/router'
import { getRouters } from '@/api/menu'
import Layout from '@/layout/index'

const permission = {
  state: {
    routes: [],
    addRoutes: []
  },
  mutations: {
    SET_ROUTES: (state, routes) => {
      state.addRoutes = routes
      state.routes = constantRoutes.concat(routes)
    }
  },
  actions: {
    // 生成路由
    GenerateRoutes({ commit }) {
      return new Promise(resolve => {
        // 向后端请求路由数据
        getRouters().then(res => {
          const sdata = JSON.parse(JSON.stringify(res.data))
          const rdata = JSON.parse(JSON.stringify(res.data))
          const sidebarRoutes = filterAsyncRouter(sdata)
          const rewriteRoutes = filterAsyncRouter(rdata, false, true)
          rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
          commit('SET_ROUTES', rewriteRoutes)
          resolve(sidebarRoutes)
        })
      })
    }
  }
}

// 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
  return asyncRouterMap.filter(route => {
    if (type && route.children) {
      route.children = filterChildren(route.children)
    }
    if (route.component) {
      // Layout ParentView 组件特殊处理
      if (route.component === 'Layout') {
        route.component = Layout
      } else if (route.component === 'ParentView') {
        route.component = ParentView
      } else if (route.component === 'InnerLink') {
        route.component = InnerLink
      } else {
        route.component = loadView(route.component)
      }
    }
    if (route.children != null && route.children && route.children.length) {
      route.children = filterAsyncRouter(route.children, route, type)
    } else {
      delete route['children']
      delete route['redirect']
    }
    return true
  })
}

权限验证指令

// 权限验证自定义指令
import store from '@/store'

function checkPermission(el, binding) {
  const { value } = binding
  const all_permission = "*:*:*";
  const permissions = store.getters && store.getters.permissions

  if (value && value instanceof Array && value.length > 0) {
    const permissionFlag = value

    const hasPermissions = permissions.some(permission => {
      return all_permission === permission || permissionFlag.includes(permission)
    })

    if (!hasPermissions) {
      el.parentNode && el.parentNode.removeChild(el)
    }
  } else {
    throw new Error(`请设置操作权限标签值`)
  }
}

export default {
  inserted(el, binding) {
    checkPermission(el, binding)
  },
  update(el, binding) {
    checkPermission(el, binding)
  }
}

2.4 部门管理

功能特性

部门管理提供了企业组织架构的管理功能,支持树形结构的部门层级关系。

核心功能清单:

  • 树形部门结构管理
  • 部门层级关系维护
  • 部门负责人设置
  • 部门状态控制
  • 部门排序功能
  • 部门数据权限关联

树形结构实现

/**
 * 构建部门树结构
 */
@Override
public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts) {
    List<SysDept> deptTrees = buildDeptTree(depts);
    return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
}

/**
 * 构建部门树
 */
public List<SysDept> buildDeptTree(List<SysDept> depts) {
    List<SysDept> returnList = new ArrayList<SysDept>();
    List<Long> tempList = new ArrayList<Long>();
    for (SysDept dept : depts) {
        tempList.add(dept.getDeptId());
    }
    for (Iterator<SysDept> iterator = depts.iterator(); iterator.hasNext();) {
        SysDept dept = (SysDept) iterator.next();
        // 如果是顶级节点, 遍历该父节点的所有子节点
        if (!tempList.contains(dept.getParentId())) {
            recursionFn(depts, dept);
            returnList.add(dept);
        }
    }
    if (returnList.isEmpty()) {
        returnList = depts;
    }
    return returnList;
}

/**
 * 递归列表
 */
private void recursionFn(List<SysDept> list, SysDept t) {
    // 得到子节点列表
    List<SysDept> childList = getChildList(list, t);
    t.setChildren(childList);
    for (SysDept tChild : childList) {
        if (hasChild(list, tChild)) {
            recursionFn(list, tChild);
        }
    }
}

2.5 字典管理

功能特性

字典管理提供了系统配置项的统一管理,支持分类管理和动态配置。

核心功能清单:

  • 字典类型管理
  • 字典数据管理
  • 字典缓存刷新
  • 字典导出功能
  • 前端字典调用

字典缓存机制

@Service
public class SysDictDataServiceImpl implements ISysDictDataService {
    
    @Autowired
    private SysDictDataMapper dictDataMapper;
    
    @Autowired 
    private RedisCache redisCache;
    
    /**
     * 根据字典类型查询字典数据
     */
    @Override
    public List<SysDictData> selectDictDataByType(String dictType) {
        List<SysDictData> dictDatas = redisCache.getCacheObject(getCacheKey(dictType));
        if (StringUtils.isNotEmpty(dictDatas)) {
            return dictDatas;
        }
        dictDatas = dictDataMapper.selectDictDataByType(dictType);
        if (StringUtils.isNotEmpty(dictDatas)) {
            redisCache.setCacheObject(getCacheKey(dictType), dictDatas);
            return dictDatas;
        }
        return null;
    }
    
    /**
     * 清空字典缓存
     */
    @Override
    public void clearDictCache() {
        Collection<String> keys = redisCache.keys(CacheConstants.SYS_DICT_KEY + "*");
        redisCache.deleteObject(keys);
    }
    
    /**
     * 设置cache key
     */
    public String getCacheKey(String configKey) {
        return CacheConstants.SYS_DICT_KEY + configKey;
    }
}

3. 系统监控模块分析

3.1 操作日志

功能特性

操作日志提供了系统操作行为的完整记录,便于审计和问题排查。

核心功能清单:

  • 操作行为自动记录
  • 日志分类管理
  • 日志查询和筛选
  • 日志详情查看
  • 日志导出功能
  • 日志清理策略

日志记录实现

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    /**
     * 模块
     */
    String title() default "";

    /**
     * 功能
     */
    BusinessType businessType() default BusinessType.OTHER;

    /**
     * 操作人类别
     */
    OperatorType operatorType() default OperatorType.MANAGE;

    /**
     * 是否保存请求的参数
     */
    boolean isSaveRequestData() default true;

    /**
     * 是否保存响应的参数
     */
    boolean isSaveResponseData() default true;
}

@Aspect
@Component
public class LogAspect {
    
    @Autowired
    private AsyncLogService asyncLogService;
    
    /**
     * 处理完请求后执行
     */
    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
        handleLog(joinPoint, controllerLog, null, jsonResult);
    }
    
    /**
     * 拦截异常操作
     */
    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
        handleLog(joinPoint, controllerLog, e, null);
    }
    
    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
        try {
            // 获取当前的用户
            LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());

            // *========数据库日志=========*//
            SysOperLog operLog = new SysOperLog();
            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
            // 请求的地址
            String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
            operLog.setOperIp(ip);
            operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());

            if (loginUser != null) {
                operLog.setOperName(loginUser.getUsername());
            }

            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 + "()");
            // 设置请求方式
            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
            // 处理设置注解上的参数
            getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
            // 保存数据库
            asyncLogService.saveSysLog(operLog);
        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("==前置通知异常==");
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }
}

3.2 登录日志

功能特性

登录日志记录用户的登录行为,用于安全监控和分析。

记录内容:

  • 登录时间和IP地址
  • 登录状态(成功/失败)
  • 浏览器和操作系统信息
  • 登录地理位置
  • 失败原因记录

登录监控实现

@Component
public class SysLoginService {
    
    @Autowired
    private TokenService tokenService;
    
    @Autowired
    private AuthenticationManager authenticationManager;
    
    @Autowired
    private RedisCache redisCache;
    
    @Autowired
    private ISysUserService userService;
    
    @Autowired
    private ISysLogininforService logininforService;
    
    /**
     * 登录验证
     */
    public String login(String username, String password, String code, String uuid) {
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
        String captcha = redisCache.getCacheObject(verifyKey);
        redisCache.deleteObject(verifyKey);
        if (captcha == null) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha)) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
            throw new CaptchaException();
        }
        
        // 用户验证
        Authentication authentication = null;
        try {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            } else {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUserId());
        // 生成token
        return tokenService.createToken(loginUser);
    }
}

3.3 在线用户

功能特性

在线用户管理提供了当前登录用户的实时监控和管理功能。

核心功能清单:

  • 在线用户列表查看
  • 用户会话信息展示
  • 强制用户下线
  • 会话超时控制
  • 多设备登录检测

会话管理实现

@Service
public class SysUserOnlineServiceImpl implements ISysUserOnlineService {
    
    @Autowired
    private RedisCache redisCache;
    
    /**
     * 查询会话集合
     */
    @Override
    public List<SysUserOnline> selectOnlineByInfo(String ipaddr, String userName, SysUserOnline userOnline) {
        List<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
        List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
        for (String key : keys) {
            LoginUser user = redisCache.getCacheObject(key);
            if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) {
                if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername())) {
                    userOnlineList.add(selectOnlineByInfo(key, user));
                }
            } else if (StringUtils.isNotEmpty(ipaddr)) {
                if (StringUtils.equals(ipaddr, user.getIpaddr())) {
                    userOnlineList.add(selectOnlineByInfo(key, user));
                }
            } else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(userOnline)) {
                if (StringUtils.equals(userName, user.getUsername())) {
                    userOnlineList.add(selectOnlineByInfo(key, user));
                }
            } else {
                userOnlineList.add(selectOnlineByInfo(key, user));
            }
        }
        Collections.reverse(userOnlineList);
        userOnlineList.removeAll(Collections.singleton(null));
        return userOnlineList;
    }
    
    /**
     * 强退用户
     */
    @Override
    public void forceLogout(String tokenId) {
        redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
    }
}

3.4 定时任务

功能特性

定时任务模块基于Quartz框架提供了完整的任务调度管理功能。

核心功能清单:

  • 任务信息CRUD管理
  • 任务执行状态监控
  • 任务执行日志记录
  • 任务手动执行
  • 任务启用/暂停控制
  • Cron表达式配置

任务调度实现

@Service
public class SysJobServiceImpl implements ISysJobService {
    
    @Autowired
    private Scheduler scheduler;
    
    @Autowired
    private SysJobMapper jobMapper;
    
    /**
     * 暂停任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int pauseJob(SysJob job) throws SchedulerException {
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
        int rows = jobMapper.updateJob(job);
        if (rows > 0) {
            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
        }
        return rows;
    }
    
    /**
     * 恢复任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int resumeJob(SysJob job) throws SchedulerException {
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
        int rows = jobMapper.updateJob(job);
        if (rows > 0) {
            scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup));
        }
        return rows;
    }
    
    /**
     * 立即运行任务
     */
    @Override
    public void run(SysJob job) throws SchedulerException {
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        JobDataMap dataMap = new JobDataMap();
        dataMap.put(ScheduleConstants.TASK_PROPERTIES, job);
        scheduler.triggerJob(ScheduleUtils.getJobKey(jobId, jobGroup), dataMap);
    }
}

4. 系统工具模块分析

4.1 代码生成器

功能特性

代码生成器是RuoYi-Vue的核心优势功能能够一键生成完整的CRUD功能代码。

核心功能清单:

  • 数据库表结构解析
  • 实体类自动生成
  • Mapper接口和XML生成
  • Service层代码生成
  • Controller层代码生成
  • 前端Vue页面生成
  • 权限配置自动生成

生成模板类型

模板类型 适用场景 生成内容
单表CRUD 普通业务表 增删改查基础功能
主子表 一对多关系表 主表+子表关联操作
树表 层级结构表 树形结构增删改查

代码生成流程

@Service
public class GenTableServiceImpl implements IGenTableService {
    
    /**
     * 生成代码(下载方式)
     */
    @Override
    public byte[] downloadCode(String tableName) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        generatorCode(tableName, zip);
        IOUtils.closeQuietly(zip);
        return outputStream.toByteArray();
    }
    
    /**
     * 生成代码(自定义路径)
     */
    @Override
    public void generatorCode(String tableName) {
        // 查询表信息
        GenTable table = genTableMapper.selectGenTableByName(tableName);
        // 设置主子表信息
        setSubTable(table);
        // 设置主键列信息
        setPkColumn(table);
        
        VelocityInitializer.initVelocity();
        
        VelocityContext context = VelocityUtils.prepareContext(table);
        
        // 获取模板列表
        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
        for (String template : templates) {
            // 渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
            tpl.merge(context, sw);
            try {
                String path = getGenPath(table, template);
                FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8);
            } catch (IOException e) {
                throw new ServiceException("渲染模板失败,表名:" + table.getTableName());
            }
        }
    }
}

模板引擎配置

/**
 * 模板工具类
 */
public class VelocityUtils {
    
    /**
     * 设置模板变量信息
     */
    public static VelocityContext prepareContext(GenTable genTable) {
        String moduleName = genTable.getModuleName();
        String businessName = genTable.getBusinessName();
        String packageName = genTable.getPackageName();
        String tplCategory = genTable.getTplCategory();
        String functionName = genTable.getFunctionName();
        
        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("tplCategory", genTable.getTplCategory());
        velocityContext.put("tableName", genTable.getTableName());
        velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】");
        velocityContext.put("ClassName", genTable.getClassName());
        velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
        velocityContext.put("moduleName", genTable.getModuleName());
        velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName()));
        velocityContext.put("businessName", genTable.getBusinessName());
        velocityContext.put("basePackage", getPackagePrefix(packageName));
        velocityContext.put("packageName", packageName);
        velocityContext.put("author", genTable.getFunctionAuthor());
        velocityContext.put("datetime", DateUtils.getDate());
        velocityContext.put("pkColumn", genTable.getPkColumn());
        velocityContext.put("importList", getImportList(genTable));
        velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
        velocityContext.put("columns", genTable.getColumns());
        velocityContext.put("table", genTable);
        setMenuVelocityContext(velocityContext, genTable);
        
        if (GenConstants.TPL_SUB.equals(tplCategory)) {
            setSubVelocityContext(velocityContext, genTable);
        }
        if (GenConstants.TPL_TREE.equals(tplCategory)) {
            setTreeVelocityContext(velocityContext, genTable);
        }
        return velocityContext;
    }
}

4.2 表单构建

功能特性

表单构建器提供了可视化的表单设计功能,支持拖拽式表单设计。

核心功能清单:

  • 拖拽式表单设计
  • 丰富的表单组件
  • 表单配置管理
  • 表单预览功能
  • 表单代码生成
  • 表单数据管理

系统接口文档

系统接口模块集成了Swagger提供了完整的API文档管理功能。

核心功能清单:

  • API接口文档自动生成
  • 接口参数说明
  • 接口在线测试
  • 接口认证支持
  • 接口分组管理

5. 权限控制体系分析

5.1 RBAC权限模型

RuoYi-Vue采用经典的RBACRole-Based Access Control权限模型实现了用户、角色、权限的解耦。

权限模型关系图

┌─────────────┐      ┌─────────────┐      ┌─────────────┐
│    用户     │ ───→ │    角色     │ ───→ │    权限     │
│   (User)    │  N:M │   (Role)    │  N:M │ (Permission)│
└─────────────┘      └─────────────┘      └─────────────┘
       │                     │                     │
       │              ┌─────────────┐              │
       └──────────────→│ 用户角色关联 │←─────────────┘
                      │(UserRole)   │
                      └─────────────┘
                             │
                      ┌─────────────┐
                      │ 角色权限关联 │
                      │(RoleMenu)   │  
                      └─────────────┘

5.2 数据权限控制

数据权限级别

权限级别 描述 应用场景
全部数据权限 可以查看所有数据 超级管理员
自定义数据权限 可以查看指定部门数据 区域经理
部门数据权限 只能查看本部门数据 部门经理
部门及以下数据权限 查看本部门及下级部门数据 主管
仅本人数据权限 只能查看自己的数据 普通员工

5.3 按钮权限控制

前端权限指令

// 权限验证指令 v-hasPermi
Vue.directive('hasPermi', {
  inserted(el, binding, vnode) {
    const { value } = binding
    const all_permission = "*:*:*";
    const permissions = store.getters && store.getters.permissions

    if (value && value instanceof Array && value.length > 0) {
      const permissionFlag = value
      const hasPermissions = permissions.some(permission => {
        return all_permission === permission || permissionFlag.includes(permission)
      })

      if (!hasPermissions) {
        el.parentNode && el.parentNode.removeChild(el)
      }
    }
  }
})

// 角色权限指令 v-hasRole  
Vue.directive('hasRole', {
  inserted(el, binding, vnode) {
    const { value } = binding
    const super_admin = "admin";
    const roles = store.getters && store.getters.roles

    if (value && value instanceof Array && value.length > 0) {
      const roleFlag = value
      const hasRole = roles.some(role => {
        return super_admin === role || roleFlag.includes(role)
      })

      if (!hasRole) {
        el.parentNode && el.parentNode.removeChild(el)
      }
    }
  }
})

6. 业务功能应用场景

6.1 典型应用场景

应用领域 具体场景 核心功能
企业内部管理 员工信息管理、权限分配 用户管理、角色管理、部门管理
政府办公系统 公文流转、审批管理 工作流、权限控制、日志审计
教育管理平台 学生信息、课程管理 数据权限、批量操作、统计分析
医疗信息系统 病例管理、权限分级 细粒度权限、数据安全、操作审计
电商后台管理 商品管理、订单处理 多角色协作、数据监控、系统集成

6.2 行业适配性分析

高适配行业

  • 制造业:生产管理、质量控制、设备维护
  • 金融业:客户管理、风险控制、合规审计
  • 零售业:商品管理、库存控制、销售分析
  • 教育行业:学员管理、课程安排、成绩管理
  • 医疗行业:病例管理、设备管理、药品管理

需要定制的行业

  • 🔧 物流行业需要集成GPS、路径优化等专业功能
  • 🔧 建筑行业:需要项目管理、工程进度等专业模块
  • 🔧 农业行业:需要农业数据采集、环境监控等功能

7. 功能扩展建议

7.1 短期功能增强

  1. 工作流引擎集成

    • 集成Activiti或Camunda工作流引擎
    • 支持复杂业务流程审批
  2. 消息通知系统

    • 站内消息推送
    • 邮件和短信通知
    • 微信企业号集成
  3. 数据可视化

    • 集成ECharts图表组件
    • 业务数据大屏展示
    • 自定义报表生成

7.2 中期功能规划

  1. 移动端支持

    • 响应式设计优化
    • 移动端App开发
    • 微信小程序集成
  2. 多租户支持

    • SaaS化改造
    • 租户数据隔离
    • 租户配置管理
  3. API开放平台

    • RESTful API规范化
    • API文档平台
    • 第三方系统集成

7.3 长期发展方向

  1. 智能化功能

    • 基于AI的数据分析
    • 智能推荐系统
    • 自然语言处理
  2. 云原生架构

    • 微服务架构改造
    • 容器化部署
    • DevOps流水线
  3. 低代码平台

    • 可视化页面设计
    • 业务流程编排
    • 零代码应用搭建

8. 总结与评估

8.1 功能完整性评估

功能模块 完整度 说明
用户权限管理 ★★★★★ 功能完善,覆盖全面
系统监控 ★★★★☆ 基础监控齐全,可扩展高级监控
代码生成 ★★★★★ 核心优势功能,大大提升开发效率
操作审计 ★★★★☆ 日志记录完整,可增强分析功能
系统工具 ★★★☆☆ 基础工具齐全,可增加更多实用工具

8.2 业务价值总结

核心业务价值:

  1. 快速开发:代码生成器等工具显著提升开发效率
  2. 权限安全:完善的权限控制体系保障数据安全
  3. 系统监控:全面的监控功能保障系统稳定运行
  4. 标准化:统一的开发规范提升代码质量
  5. 可扩展:模块化架构支持业务快速扩展

适用企业特征:

  • 中小型企业管理系统开发
  • 需要快速上线的项目
  • 对安全性要求较高的应用
  • 希望降低开发成本的团队
  • 需要标准化开发流程的组织

RuoYi-Vue以其完整的功能体系、成熟的技术架构和良好的扩展性为企业级后台管理系统的开发提供了优秀的基础框架能够满足大部分企业的业务需求是企业数字化转型的理想技术选择。