# RuoYi-Vue 开发指南 ## 1. 开发环境准备 ### 1.1 环境要求 #### 基础环境要求 | 组件 | 版本要求 | 推荐版本 | 说明 | |------|----------|----------|------| | **JDK** | 1.8+ | JDK 1.8.0_202 | 确保JAVA_HOME配置正确 | | **Maven** | 3.6+ | Maven 3.6.3 | 依赖管理和项目构建 | | **MySQL** | 5.7+ | MySQL 8.0.28 | 数据库服务 | | **Redis** | 6.0+ | Redis 6.2.7 | 缓存服务 | | **Node.js** | 14+ | Node.js 16.17.0 | 前端开发环境 | | **npm** | 6.14+ | npm 8.15.0 | 前端包管理器 | #### IDE推荐配置 **后端开发IDE:** - ✅ **IntelliJ IDEA** (推荐) - 安装插件:Lombok、MyBatis Log Plugin、Maven Helper - ✅ **Eclipse** + Spring Tool Suite - ✅ **Visual Studio Code** + Java Extension Pack **前端开发IDE:** - ✅ **Visual Studio Code** (推荐) - 安装插件:Vetur、ESLint、Prettier、Auto Rename Tag - ✅ **WebStorm** ### 1.2 环境安装指南 #### JDK安装配置 ```bash # 1. 下载JDK 1.8 # https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html # 2. 配置环境变量 (Windows) set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_202 set PATH=%JAVA_HOME%\bin;%PATH% # 3. 配置环境变量 (macOS/Linux) export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home export PATH=$JAVA_HOME/bin:$PATH # 4. 验证安装 java -version javac -version ``` #### MySQL安装配置 ```bash # 1. 安装MySQL (使用Docker,推荐) docker run -d \ --name mysql \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=password \ -e MYSQL_DATABASE=ry-vue \ mysql:8.0 # 2. 创建数据库 mysql -u root -p CREATE DATABASE `ry-vue` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 3. 导入初始化脚本 mysql -u root -p ry-vue < sql/ry_20210908.sql mysql -u root -p ry-vue < sql/quartz.sql ``` #### Redis安装配置 ```bash # 1. 安装Redis (使用Docker,推荐) docker run -d \ --name redis \ -p 6379:6379 \ redis:6.2-alpine # 2. 本地安装 (macOS) brew install redis brew services start redis # 3. 本地安装 (CentOS/RHEL) yum install redis systemctl start redis systemctl enable redis # 4. 验证安装 redis-cli ping # 应该返回 PONG ``` #### Node.js安装 ```bash # 1. 使用NVM安装 (推荐) curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash nvm install 16.17.0 nvm use 16.17.0 # 2. 直接下载安装 # https://nodejs.org/ # 3. 验证安装 node -v npm -v # 4. 配置国内镜像源 (可选) npm config set registry https://registry.npmmirror.com/ ``` ## 2. 项目快速启动 ### 2.1 项目获取与配置 #### 项目下载 ```bash # 1. 克隆项目 (如果是Git仓库) git clone https://gitee.com/y_project/RuoYi-Vue.git cd RuoYi-Vue # 2. 或者直接下载解压项目压缩包 ``` #### 数据库配置 ```yaml # ruoyi-admin/src/main/resources/application-druid.yml spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver druid: # 主库数据源 master: url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: password # 从库数据源 (可选) slave: enabled: false url: username: password: ``` #### Redis配置 ```yaml # ruoyi-admin/src/main/resources/application.yml spring: redis: host: localhost port: 6379 password: database: 0 timeout: 10s lettuce: pool: min-idle: 0 max-idle: 8 max-active: 8 max-wait: -1ms ``` ### 2.2 后端启动 ```bash # 1. 进入项目根目录 cd RuoYi-Vue-master # 2. Maven清理和编译 mvn clean install -Dmaven.test.skip=true # 3. 启动应用 (方式一:Maven命令) cd ruoyi-admin mvn spring-boot:run # 4. 启动应用 (方式二:java命令) cd ruoyi-admin/target java -jar ruoyi-admin.jar # 5. 启动应用 (方式三:脚本启动) ./ry.sh start # 6. 查看启动日志 tail -f logs/sys-info.log ``` #### 启动验证 ```bash # 检查应用是否启动成功 curl http://localhost:8080/captchaImage # 检查健康状态 curl http://localhost:8080/actuator/health # 查看端口占用 netstat -an | grep 8080 ``` ### 2.3 前端启动 ```bash # 1. 进入前端项目目录 cd ruoyi-ui # 2. 安装依赖 npm install # 3. 启动开发服务器 npm run dev # 4. 构建生产版本 npm run build:prod # 5. 预览构建结果 npm run preview ``` #### 前端配置文件 ```javascript // ruoyi-ui/.env.development # 开发环境配置 ENV = 'development' # 若依管理系统/开发环境 VUE_APP_TITLE = 若依管理系统 # 开发环境配置 VUE_APP_ENV = 'development' # 若依管理系统/开发环境 VUE_APP_BASE_API = '/dev-api' ``` ### 2.4 访问系统 #### 系统访问地址 | 服务 | 访问地址 | 默认账号 | |------|----------|----------| | **前端系统** | http://localhost | admin / admin123 | | **后端接口** | http://localhost:8080 | - | | **接口文档** | http://localhost:8080/swagger-ui.html | - | | **Druid监控** | http://localhost:8080/druid | admin / 123456 | #### 默认管理员账号 ``` 用户名:admin 密码:admin123 ``` ## 3. 开发规范与约定 ### 3.1 代码规范 #### Java代码规范 **1. 命名规范** ```java // 类名:大驼峰命名法 public class SysUserController { // 常量:全大写,下划线分隔 private static final String USER_CACHE_KEY = "user:cache:"; // 变量:小驼峰命名法 private String userName; // 方法:小驼峰命名法,动词开头 public AjaxResult getUserList() { return success(); } } ``` **2. 注释规范** ```java /** * 用户信息 * * @author ruoyi * @date 2024-01-01 */ @Entity @Table(name = "sys_user") public class SysUser extends BaseEntity { private static final long serialVersionUID = 1L; /** 用户ID */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long userId; /** 用户账号 */ @NotBlank(message = "用户账号不能为空") @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符") private String userName; /** * 获取用户信息 * * @param userId 用户ID * @return 用户信息 */ public SysUser getUserById(Long userId) { // 实现逻辑 return null; } } ``` **3. 异常处理规范** ```java @RestControllerAdvice public class GlobalExceptionHandler { private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 业务异常 */ @ExceptionHandler(ServiceException.class) public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request) { log.error(e.getMessage(), e); Integer code = e.getCode(); return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage()); } /** * 权限校验异常 */ @ExceptionHandler(AccessDeniedException.class) public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage()); return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限,请联系管理员授权"); } } ``` #### JavaScript代码规范 **1. 命名规范** ```javascript // 常量:全大写,下划线分隔 const API_BASE_URL = '/dev-api'; // 变量:小驼峰命名法 const userName = 'admin'; // 函数:小驼峰命名法,动词开头 function getUserList() { return request({ url: '/system/user/list', method: 'get' }); } // 组件名:大驼峰命名法 export default { name: 'UserList', components: { UserDialog } }; ``` **2. Vue组件规范** ```vue ``` ### 3.2 数据库设计规范 #### 表设计规范 **1. 表命名规范** ```sql -- 系统表前缀:sys_ CREATE TABLE `sys_user` ( `user_id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID', PRIMARY KEY (`user_id`) ) ENGINE=InnoDB COMMENT='用户信息表'; -- 业务表前缀:根据模块命名 CREATE TABLE `biz_order` ( `order_id` bigint NOT NULL AUTO_INCREMENT COMMENT '订单ID', PRIMARY KEY (`order_id`) ) ENGINE=InnoDB COMMENT='订单信息表'; ``` **2. 字段设计规范** ```sql -- 标准字段设计 CREATE TABLE `sys_user` ( -- 主键:bigint,自增 `user_id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID', -- 业务字段:合适的数据类型和长度 `user_name` varchar(30) NOT NULL COMMENT '用户账号', `nick_name` varchar(30) NOT NULL COMMENT '用户昵称', `email` varchar(50) DEFAULT '' COMMENT '用户邮箱', `phonenumber` varchar(11) DEFAULT '' COMMENT '手机号码', `sex` char(1) DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)', `status` char(1) DEFAULT '0' COMMENT '帐号状态(0正常 1停用)', `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', -- 审计字段:每张表必须包含 `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`), UNIQUE KEY `uk_user_name` (`user_name`), KEY `idx_status` (`status`), KEY `idx_create_time` (`create_time`) ) ENGINE=InnoDB AUTO_INCREMENT=100 COMMENT='用户信息表'; ``` **3. 索引设计规范** ```sql -- 主键索引:每张表必须有主键 PRIMARY KEY (`id`) -- 唯一索引:业务唯一字段 UNIQUE KEY `uk_user_name` (`user_name`) -- 普通索引:经常查询的字段 KEY `idx_status` (`status`) KEY `idx_create_time` (`create_time`) -- 复合索引:多字段组合查询 KEY `idx_dept_status` (`dept_id`, `status`) -- 外键索引:关联字段 KEY `idx_dept_id` (`dept_id`) ``` ### 3.3 API设计规范 #### RESTful API设计 **1. URL设计规范** ```java // 资源型URL,使用名词复数形式 @RequestMapping("/system/users") @RestController public class SysUserController { // GET /system/users - 获取用户列表 @GetMapping public TableDataInfo list(SysUser user) { startPage(); List list = userService.selectUserList(user); return getDataTable(list); } // GET /system/users/{id} - 获取单个用户 @GetMapping("/{userId}") public AjaxResult getInfo(@PathVariable("userId") Long userId) { return AjaxResult.success(userService.selectUserById(userId)); } // POST /system/users - 新增用户 @PostMapping public AjaxResult add(@Validated @RequestBody SysUser user) { return toAjax(userService.insertUser(user)); } // PUT /system/users/{id} - 更新用户 @PutMapping("/{userId}") public AjaxResult edit(@Validated @RequestBody SysUser user) { return toAjax(userService.updateUser(user)); } // DELETE /system/users/{id} - 删除用户 @DeleteMapping("/{userIds}") public AjaxResult remove(@PathVariable Long[] userIds) { return toAjax(userService.deleteUserByIds(userIds)); } } ``` **2. 响应格式规范** ```java // 统一响应格式 public class AjaxResult extends HashMap { private static final long serialVersionUID = 1L; /** 状态码 */ public static final String CODE_TAG = "code"; /** 返回内容 */ public static final String MSG_TAG = "msg"; /** 数据对象 */ public static final String DATA_TAG = "data"; /** * 状态类型 */ public enum Type { /** 成功 */ SUCCESS(200), /** 警告 */ WARN(301), /** 错误 */ ERROR(500); private final int value; } } // 成功响应示例 { "code": 200, "msg": "操作成功", "data": { "userId": 1, "userName": "admin", "nickName": "管理员" } } // 分页响应示例 { "code": 200, "msg": "查询成功", "rows": [ { "userId": 1, "userName": "admin" } ], "total": 100 } // 错误响应示例 { "code": 500, "msg": "用户名不能为空" } ``` ## 4. 开发最佳实践 ### 4.1 后端开发实践 #### 分层架构实践 **1. Controller层最佳实践** ```java @RestController @RequestMapping("/system/user") public class SysUserController extends BaseController { @Autowired private ISysUserService userService; /** * 获取用户列表 */ @PreAuthorize("@ss.hasPermi('system:user:list')") @GetMapping("/list") public TableDataInfo list(SysUser user) { startPage(); // 开启分页 List list = userService.selectUserList(user); return getDataTable(list); // 返回分页结果 } /** * 新增用户 */ @PreAuthorize("@ss.hasPermi('system:user:add')") @Log(title = "用户管理", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@Validated @RequestBody SysUser user) { // 1. 参数校验 if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user.getUserName()))) { return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); } // 2. 设置默认值 user.setCreateBy(getUsername()); user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); // 3. 调用服务层 return toAjax(userService.insertUser(user)); } } ``` **2. Service层最佳实践** ```java @Service public class SysUserServiceImpl implements ISysUserService { @Autowired private SysUserMapper userMapper; @Autowired private SysUserRoleMapper userRoleMapper; /** * 新增用户信息 */ @Override @Transactional public int insertUser(SysUser user) { // 1. 新增用户信息 int rows = userMapper.insertUser(user); // 2. 新增用户与角色管理 insertUserRole(user); return rows; } /** * 新增用户角色信息 */ public void insertUserRole(SysUser user) { Long[] roles = user.getRoleIds(); if (StringUtils.isNotNull(roles)) { // 新增用户与角色管理 List list = new ArrayList(); for (Long roleId : roles) { SysUserRole ur = new SysUserRole(); ur.setUserId(user.getUserId()); ur.setRoleId(roleId); list.add(ur); } if (list.size() > 0) { userRoleMapper.batchUserRole(list); } } } } ``` **3. Mapper层最佳实践** ```java @Mapper public interface SysUserMapper { /** * 根据条件分页查询用户列表 * * @param sysUser 用户信息 * @return 用户信息集合信息 */ public List selectUserList(SysUser sysUser); /** * 新增用户信息 * * @param user 用户信息 * @return 结果 */ public int insertUser(SysUser user); } ``` ```xml select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_id, d.parent_id, d.dept_name, d.order_num, d.leader, d.status as dept_status, r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status from sys_user u left join sys_dept d on u.dept_id = d.dept_id left join sys_user_role ur on u.user_id = ur.user_id left join sys_role r on r.role_id = ur.role_id insert into sys_user( user_id, dept_id, user_name, nick_name, email, avatar, phonenumber, sex, password, status, create_by, remark, create_time )values( #{userId}, #{deptId}, #{userName}, #{nickName}, #{email}, #{avatar}, #{phonenumber}, #{sex}, #{password}, #{status}, #{createBy}, #{remark}, sysdate() ) ``` #### 缓存使用实践 ```java @Service public class SysDictDataServiceImpl implements ISysDictDataService { @Autowired private RedisCache redisCache; @Autowired private SysDictDataMapper dictDataMapper; /** * 根据字典类型查询字典数据 */ @Override public List selectDictDataByType(String dictType) { String cacheKey = getCacheKey(dictType); List dictDatas = redisCache.getCacheObject(cacheKey); if (StringUtils.isNotEmpty(dictDatas)) { return dictDatas; } dictDatas = dictDataMapper.selectDictDataByType(dictType); if (StringUtils.isNotEmpty(dictDatas)) { redisCache.setCacheObject(cacheKey, dictDatas, 30, TimeUnit.MINUTES); } return dictDatas; } /** * 更新字典数据 */ @Override public int updateDictData(SysDictData dictData) { int row = dictDataMapper.updateDictData(dictData); if (row > 0) { // 清除相关缓存 redisCache.deleteObject(getCacheKey(dictData.getDictType())); } return row; } private String getCacheKey(String dictType) { return CacheConstants.SYS_DICT_KEY + dictType; } } ``` ### 4.2 前端开发实践 #### Vue组件开发实践 **1. 页面组件结构** ```vue ``` **2. API调用封装** ```javascript // api/system/user.js import request from '@/utils/request' // 查询用户列表 export function listUser(query) { return request({ url: '/system/user/list', method: 'get', params: query }) } // 查询用户详细 export function getUser(userId) { return request({ url: '/system/user/' + userId, method: 'get' }) } // 新增用户 export function addUser(data) { return request({ url: '/system/user', method: 'post', data: data }) } // 修改用户 export function updateUser(data) { return request({ url: '/system/user', method: 'put', data: data }) } // 删除用户 export function delUser(userId) { return request({ url: '/system/user/' + userId, method: 'delete' }) } ``` **3. 工具函数封装** ```javascript // utils/index.js /** * 参数处理 * @param {*} params 参数 */ export function tansParams(params) { let result = '' for (const propName of Object.keys(params)) { const value = params[propName]; var part = encodeURIComponent(propName) + "="; if (value !== null && typeof(value) !== "undefined") { if (typeof value === 'object') { for (const key of Object.keys(value)) { if (value[key] !== null && typeof (value[key]) !== 'undefined') { let params = propName + '[' + key + ']'; var subPart = encodeURIComponent(params) + "="; result += subPart + encodeURIComponent(value[key]) + "&"; } } } else { result += part + encodeURIComponent(value) + "&"; } } } return result } /** * 构造树型结构数据 * @param {*} data 数据源 * @param {*} id id字段 默认 'id' * @param {*} parentId 父节点字段 默认 'parentId' * @param {*} children 孩子节点字段 默认 'children' */ export function handleTree(data, id, parentId, children) { let config = { id: id || 'id', parentId: parentId || 'parentId', childrenList: children || 'children' }; var childrenListMap = {}; var nodeIds = {}; var tree = []; for (let d of data) { let parentId = d[config.parentId]; if (childrenListMap[parentId] == null) { childrenListMap[parentId] = []; } nodeIds[d[config.id]] = d; childrenListMap[parentId].push(d); } for (let d of data) { let parentId = d[config.parentId]; if (nodeIds[parentId] == null) { tree.push(d); } } for (let t of tree) { adaptToChildrenList(t); } function adaptToChildrenList(o) { if (childrenListMap[o[config.id]] !== null) { o[config.childrenList] = childrenListMap[o[config.id]]; } if (o[config.childrenList]) { for (let c of o[config.childrenList]) { adaptToChildrenList(c); } } } return tree; } ``` ## 5. 代码生成器使用指南 ### 5.1 使用流程 #### Step 1: 创建数据库表 ```sql -- 创建示例表 DROP TABLE IF EXISTS `test_demo`; CREATE TABLE `test_demo` ( `demo_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', `demo_name` varchar(30) DEFAULT '' COMMENT '名称', `demo_type` char(1) DEFAULT '0' COMMENT '类型(0正常 1停用)', `demo_status` char(1) DEFAULT '0' COMMENT '状态(0正常 1删除)', `demo_content` longtext 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 (`demo_id`) ) ENGINE=InnoDB COMMENT = '测试演示表'; ``` #### Step 2: 导入表到代码生成 1. 登录系统,进入 `系统工具 -> 代码生成` 2. 点击 `导入` 按钮,选择需要生成代码的表 3. 点击 `导入` 确认 #### Step 3: 配置生成信息 ```java // 基本信息配置 表名称: test_demo 表描述: 测试演示表 实体类名称: TestDemo 作者: ruoyi 生成包路径: com.ruoyi.system 生成模块名: system 生成业务名: demo 生成功能名: 测试演示 上级菜单: 系统工具 ``` #### Step 4: 字段信息配置 | 字段名 | 字段描述 | 字段类型 | Java类型 | Java字段 | 是否必填 | 是否为插入字段 | 是否为编辑字段 | 是否为列表字段 | 是否为查询字段 | 查询方式 | 显示类型 | |--------|----------|----------|----------|----------|----------|---------------|---------------|---------------|---------------|----------|----------| | demo_id | 主键 | bigint | Long | demoId | 否 | 否 | 否 | 否 | 否 | = | 文本框 | | demo_name | 名称 | varchar(30) | String | demoName | 是 | 是 | 是 | 是 | 是 | LIKE | 文本框 | | demo_type | 类型 | char(1) | String | demoType | 否 | 是 | 是 | 是 | 是 | = | 选择框 | | demo_status | 状态 | char(1) | String | demoStatus | 否 | 是 | 是 | 是 | 是 | = | 单选框 | | demo_content | 内容 | longtext | String | demoContent | 否 | 是 | 是 | 否 | 否 | = | 文本域 | #### Step 5: 生成代码 1. 配置完成后,点击 `生成代码` 按钮 2. 下载生成的代码包 3. 解压并导入到项目中 ### 5.2 生成的代码结构 ``` ruoyi-system/ ├── domain/ │ └── TestDemo.java # 实体类 ├── mapper/ │ ├── TestDemoMapper.java # Mapper接口 │ └── TestDemoMapper.xml # Mapper XML ├── service/ │ ├── ITestDemoService.java # Service接口 │ └── impl/ │ └── TestDemoServiceImpl.java # Service实现 └── controller/ └── TestDemoController.java # Controller ruoyi-ui/src/ ├── api/system/ │ └── demo.js # API接口 └── views/system/demo/ └── index.vue # 页面组件 ``` ### 5.3 生成后的集成步骤 #### Step 1: 后端集成 ```java // 1. 确认文件已正确放置在对应目录 // 2. 无需额外配置,Spring Boot会自动扫描 // 3. 如果使用了自定义配置,需要检查包扫描路径 @SpringBootApplication @ComponentScan(basePackages = {"com.ruoyi"}) public class RuoYiApplication { public static void main(String[] args) { SpringApplication.run(RuoYiApplication.class, args); } } ``` #### Step 2: 前端集成 ```javascript // 1. 将生成的 demo.js 放置到 src/api/system/ 目录 // 2. 将生成的 index.vue 放置到 src/views/system/demo/ 目录 // 3. 在路由中添加新的路由配置(如果需要) // router/index.js { path: '/system/demo', component: Layout, hidden: true, children: [ { path: 'index', component: () => import('@/views/system/demo/index'), name: 'Demo', meta: { title: '测试演示', icon: '' } } ] } ``` #### Step 3: 菜单配置 1. 登录系统,进入 `系统管理 -> 菜单管理` 2. 新增菜单项: ``` 菜单名称: 测试演示 上级菜单: 系统工具 菜单类型: 菜单 路由地址: demo 组件路径: system/demo/index 权限字符: system:demo:list ``` 3. 新增按钮权限: ``` 新增: system:demo:add 修改: system:demo:edit 删除: system:demo:remove 导出: system:demo:export ``` ## 6. 部署指南 ### 6.1 开发环境部署 #### 本地开发部署 ```bash # 1. 启动MySQL和Redis服务 docker-compose up -d mysql redis # 2. 导入数据库脚本 mysql -u root -p ry-vue < sql/ry_20210908.sql # 3. 启动后端服务 cd ruoyi-admin mvn spring-boot:run # 4. 启动前端服务 cd ruoyi-ui npm install npm run dev # 5. 访问系统 # 前端: http://localhost # 后端: http://localhost:8080 ``` ### 6.2 生产环境部署 #### 传统部署方式 **1. 后端部署** ```bash # 1. Maven打包 mvn clean package -Dmaven.test.skip=true # 2. 上传jar包到服务器 scp ruoyi-admin/target/ruoyi-admin.jar user@server:/opt/ruoyi/ # 3. 创建启动脚本 cat > /opt/ruoyi/start.sh << 'EOF' #!/bin/bash export JAVA_OPTS="-Xms512m -Xmx2048m -Xss256k" export SERVER_PORT=8080 export SPRING_PROFILES_ACTIVE=prod nohup java $JAVA_OPTS -jar ruoyi-admin.jar \ --server.port=$SERVER_PORT \ --spring.profiles.active=$SPRING_PROFILES_ACTIVE \ > logs/application.log 2>&1 & echo $! > ruoyi.pid echo "RuoYi started with PID: $(cat ruoyi.pid)" EOF chmod +x start.sh # 4. 启动服务 ./start.sh ``` **2. 前端部署** ```bash # 1. 构建生产版本 npm run build:prod # 2. 上传到Web服务器 scp -r dist/ user@server:/var/www/html/ruoyi/ # 3. 配置Nginx cat > /etc/nginx/conf.d/ruoyi.conf << 'EOF' server { listen 80; server_name your-domain.com; location / { root /var/www/html/ruoyi; index index.html; try_files $uri $uri/ /index.html; } location /prod-api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } EOF # 4. 重启Nginx nginx -s reload ``` #### Docker容器化部署 **1. 创建Dockerfile** ```dockerfile # 后端Dockerfile FROM openjdk:8-jre-alpine WORKDIR /app COPY ruoyi-admin/target/ruoyi-admin.jar app.jar ENV JAVA_OPTS="-Xms512m -Xmx1024m" EXPOSE 8080 ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"] ``` ```dockerfile # 前端Dockerfile FROM nginx:alpine COPY dist/ /usr/share/nginx/html/ COPY nginx.conf /etc/nginx/nginx.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` **2. 创建docker-compose.yml** ```yaml version: '3.8' services: mysql: image: mysql:8.0 container_name: ruoyi-mysql restart: always environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: ry-vue ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql - ./sql:/docker-entrypoint-initdb.d redis: image: redis:6.2-alpine container_name: ruoyi-redis restart: always ports: - "6379:6379" volumes: - redis_data:/data ruoyi-backend: build: . container_name: ruoyi-backend restart: always ports: - "8080:8080" environment: SPRING_PROFILES_ACTIVE: prod SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 SPRING_REDIS_HOST: redis depends_on: - mysql - redis ruoyi-frontend: build: context: . dockerfile: Dockerfile.frontend container_name: ruoyi-frontend restart: always ports: - "80:80" depends_on: - ruoyi-backend volumes: mysql_data: redis_data: ``` **3. 部署命令** ```bash # 1. 构建并启动所有服务 docker-compose up -d # 2. 查看服务状态 docker-compose ps # 3. 查看日志 docker-compose logs -f ruoyi-backend # 4. 停止服务 docker-compose down ``` ### 6.3 监控和运维 #### 应用监控配置 ```yaml # application-prod.yml management: endpoints: web: exposure: include: health,info,metrics endpoint: health: show-details: always metrics: export: prometheus: enabled: true ``` #### 日志配置 ```xml logs/application.log logs/application.%d{yyyy-MM-dd}.log 30 1GB %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n ``` ## 7. 常见问题与解决方案 ### 7.1 环境问题 **Q: Maven依赖下载失败** ```bash # A: 配置国内镜像源 # ~/.m2/settings.xml aliyun central Aliyun Central https://maven.aliyun.com/repository/central ``` **Q: NPM包安装失败** ```bash # A: 使用国内镜像 npm config set registry https://registry.npmmirror.com/ # 或使用yarn yarn config set registry https://registry.npmmirror.com/ ``` **Q: MySQL连接失败** ```yaml # A: 检查数据库配置和权限 spring: datasource: url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true ``` ### 7.2 开发问题 **Q: 跨域问题** ```java // A: 后端跨域配置 @Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOriginPattern("*"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); config.setMaxAge(1800L); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } } ``` **Q: 权限验证失败** ```java // A: 检查权限配置和用户角色 @PreAuthorize("@ss.hasPermi('system:user:list')") // 确保用户拥有对应权限 ``` ### 7.3 部署问题 **Q: 前端页面空白** ```javascript // A: 检查publicPath配置 // vue.config.js module.exports = { publicPath: process.env.NODE_ENV === "production" ? "/" : "/", } ``` **Q: 后端接口404** ```yaml # A: 检查context-path配置 server: servlet: context-path: / ``` ## 8. 总结 本开发指南提供了RuoYi-Vue项目从环境搭建到生产部署的完整开发流程,涵盖了: ✅ **环境准备**:详细的开发环境安装和配置指南 ✅ **快速启动**:项目快速启动和验证步骤 ✅ **开发规范**:代码规范和API设计最佳实践 ✅ **开发实践**:分层架构和组件开发最佳实践 ✅ **代码生成**:代码生成器的使用方法和集成步骤 ✅ **部署指南**:从开发环境到生产环境的部署方案 ✅ **问题解决**:常见问题的解决方案 通过遵循本指南,开发者可以: - 快速搭建开发环境并启动项目 - 掌握项目的开发规范和最佳实践 - 高效使用代码生成器提升开发效率 - 顺利完成项目的部署和上线 - 解决开发过程中的常见问题 RuoYi-Vue作为一个成熟的企业级开发框架,为快速构建高质量的管理系统提供了坚实的基础。结合本开发指南,开发团队能够快速上手并充分发挥框架的优势,提升项目开发效率和质量。