从0到1入门若依RuoYi框架
·
////////////////////////////////////////////////////////////////////
// _ooOoo_ //
// o8888888o //
// 88" . "88 //
// (| ^_^ |) //
// O\ = /O //
// ____/`---'\____ //
// .' \\| |// `. //
// / \\||| : |||// \ //
// / _||||| -:- |||||- \ //
// | | \\\ - /// | | //
// | \_| ''\---/'' | | //
// \ .-\__ `-` ___/-. / //
// ___`. .' /--.--\ `. . ___ //
// ."" '< `.___\_<|>_/___.' >'"". //
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
// \ \ `-. \_ __\ /__ _/ .-` / / //
// ========`-.____`-.___\_____/___.-`____.-'======== //
// `=---=' //
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
// 佛祖保佑 永不宕机 永无BUG //
////////////////////////////////////////////////////////////////////
一、快速入门——自动生成代码功能
①启动前端
执行命令
npm install npm run dev
启动完成后,浏览器自动打开若依后台管理登录页面
②导入数据库表
准备SQL并导入数据库,在左侧列表找到“系统工具-代码生成”
导入需要生成代码的数据库表
③生成代码
导入后将页面拖动到底部,最后一个表即为新导入的数据库表
点击“编辑”可以进行详细设置
选择后点击“生成”
浏览器自动下载导出.zip文件
解压后
- main——后端代码
- vue——前端代码
- ***.sql——动态菜单的SQL文件
然后使用CV大法导入到对应的项目文件中
二、功能详解——权限控制
RBAC(Role-Based Access Control,基于角色的访问控制)是一种广泛使用的访问控制模型,通过角色来分配和管理用户的菜单权限。
(0基础,学IT,月薪过万,就来黑马程序员!)


通过系统管理进行简单配置即可实现权限控制
三、功能详解——数据字典
用于维护系统中常见的静态数据。如:性别,状态...



四、功能详解——其他功能





五、功能详解——监控相关





六、功能详解——定时任务

示例:每隔5秒控制台输出当前时间


七、功能详解——表单构建

示例:
①制作表单并导出,通过拖拽的方式即可快速完成表单的构建

②复制到对应的前端工程
③创建动态菜单,配置路由地址和组件路径

八、功能详解——代码生成


九、功能详解——系统工具

十、项目结构
①ruoyi-admin


②ruoyi-common

③ruoyi-framework

④ruoyi-system
⑤后端模块依赖关系

⑥前端Vue

⑦表结构

十一、前端源码分析
①html
<el-form
:model="queryParams" <!-- 表单数据对象,表单内的字段会与queryParams中的属性双向绑定 -->
ref="queryRef" <!-- 表单的引用标识,可通过this.$refs.queryRef在Vue实例中访问该表单实例,用于表单验证、重置等操作 -->
:inline="true" <!-- 开启行内表单模式,表单项会水平排列,适合搜索框等紧凑布局场景 -->
v-show="showSearch" <!-- 根据showSearch变量的值控制表单显示/隐藏,v-show通过CSS display实现,元素始终存在于DOM中 -->
label-width="68px" <!-- 设置表单标签的固定宽度为68px,确保标签对齐,提升表单美观度 -->
>
</el-form>
<el-form-item label="课程编码" prop="code">
<el-input
v-model="queryParams.code" <!-- 双向绑定查询参数对象的 code 字段,实时同步输入值 -->
placeholder="请输入课程编码" <!-- 输入框默认提示文本,引导用户输入 -->
clearable <!-- 开启输入框右侧的「清空」按钮,点击可快速清空内容 -->
@keyup.enter="handleQuery" <!-- 监听键盘回车键事件,触发查询函数 handleQuery -->
/>
</el-form-item>
<!-- 课程学科选择器:使用 Element UI 的 el-select 组件实现 -->
<el-select
v-model="queryParams.subject" <!-- 双向绑定:选中的学科值会同步到 queryParams.subject -->
placeholder="请选择课程学科" <!-- 占位提示:未选择时显示的提示文本 -->
clearable <!-- 清空功能:允许用户点击清除已选内容 -->
>
<!-- 遍历课程学科字典数组:
course_subject 是预先定义的字典数组(格式:[{label: '语文', value: 'chinese'}, ...]) -->
<el-option
v-for="dict in course_subject"
:key="dict.value" <!-- 唯一标识:Vue 渲染列表时需要唯一 key,避免重复渲染问题 -->
:label="dict.label" <!-- 选项显示文本:用户看到的下拉选项文字(如“数学”) -->
:value="dict.value" <!-- 选项实际值:选中后绑定到 v-model 的值(如“math”) -->
/>
</el-select>
<!-- Element UI 栅格系统的列组件,:span="1.5" 表示该列占栅格系统的 1.5 份(基于 24 分栏体系) -->
<el-col :span="1.5">
<!-- Element UI 按钮组件,实现「修改」功能 -->
<el-button
type="success" <!-- 按钮类型:success 对应绿色主题 -->
plain <!-- 朴素按钮样式(仅保留边框和文字颜色,无背景色) -->
icon="Edit" <!-- 按钮左侧图标:Edit 图标(需确保图标已注册或引入) -->
:disabled="single" <!-- 动态禁用:根据 single 变量的值决定是否禁用按钮(true 则禁用) -->
@click="handleUpdate" <!-- 点击事件:触发 handleUpdate 方法(需在组件 methods 中定义) -->
v-hasPermi="['course:course:edit']" <!-- 权限控制指令:检查用户是否拥有「course:course:edit」权限,无权限则隐藏/禁用按钮(需自定义指令支持) -->
>
修改 <!-- 按钮显示的文本内容 -->
</el-button>
</el-col>
<!-- 数据展示表格 start -->
<!--
el-table:Element UI 表格组件,用于展示课程数据
v-loading:绑定加载状态,加载时显示加载动画(loading 为组件内定义的响应式变量)
:data:表格数据源,绑定课程列表数据(courseList 为组件内定义的响应式数组)
@selection-change:可选事件(代码中未完整写处理函数,通常用于监听行选择变化,如多选操作)
-->
<el-table v-loading="loading" :data="courseList" @selection-change>
<!-- 多选列:用于批量选择行数据,固定宽度 55px,内容居中 -->
<el-table-column type="selection" width="55" align="center" />
<!-- 课程ID列:显示课程的唯一标识,prop 绑定数据中的 `id` 字段 -->
<el-table-column label="课程id" align="center" prop="id" />
<!-- 课程编码列:显示课程编码,prop 绑定数据中的 `code` 字段 -->
<el-table-column label="课程编码" align="center" prop="code" />
<!-- 课程学科列:通过字典组件展示(若依框架的 dict-tag 组件) -->
<el-table-column label="课程学科" align="center" prop="subject">
<!--
作用域插槽(#default="scope"):获取当前行数据(scope.row 为当前行对象)
dict-tag:若依封装的字典标签组件,用于将字典值转换为文本
:options:绑定字典数据源(course_subject 为组件内定义的字典数据,如学科枚举)
:value:绑定当前行的学科值(scope.row.subject),用于匹配字典文本
-->
<template #default="scope">
<dict-tag :options="course_subject" :value="scope.row.subject"/>
</template>
</el-table-column>
<!-- 课程名称列:显示课程名称,prop 绑定数据中的 `name` 字段 -->
<el-table-column label="课程名称" align="center" prop="name" />
<!-- 价格列:显示课程价格,prop 绑定数据中的 `price` 字段 -->
<el-table-column label="价格" align="center" prop="price" />
<!-- 适用人群列:显示课程适用人群,prop 绑定数据中的 `applicablePerson` 字段 -->
<el-table-column label="适用人群" align="center" prop="applicablePerson" />
<!-- 课程介绍列:显示课程描述信息,prop 绑定数据中的 `info` 字段 -->
<el-table-column label="课程介绍" align="center" prop="info" />
<!-- 操作列:自定义操作按钮,设置特殊样式(small-padding fixed-width) -->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<!--
修改按钮:
- link 类型:文字按钮样式
- type="primary":主题色(通常为蓝色)
- icon="Edit":Element UI 内置编辑图标
- @click:点击触发 handleUpdate 方法(传入当前行数据 scope.row)
- v-hasPermi:若依权限指令,判断用户是否有 `course:course:edit` 权限,有权限才显示按钮
-->
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['course:course:edit']">修改</el-button>
<!--
删除按钮:
- 逻辑同修改按钮,权限为 `course:course:remove`,点击触发 handleDelete 方法
-->
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['course:course:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件:用于数据列表的分页展示,以下为各属性说明 -->
<pagination
v-show="total>0" <!-- 控制分页组件的显示逻辑:仅当总数据量 total 大于 0 时,才渲染该组件 -->
:total="total" <!-- 向分页组件传递总数据条数,用于计算总页数等逻辑 -->
v-model:page="queryParams.pageNum" <!-- 双向绑定当前页码:分页组件的页码变化会同步更新 queryParams.pageNum -->
v-model:limit="queryParams.pageSize" <!-- 双向绑定每页条数:分页组件的每页数量变化会同步更新 queryParams.pageSize -->
@pagination="getList" <!-- 监听分页组件的 pagination 事件(如页码切换、每页条数变化),触发时调用 getList 函数重新获取数据列表 -->
/>
<!-- 课程管理的添加/修改对话框组件 -->
<el-dialog
:title="title" // 对话框标题,新增时为"添加课程",编辑时为"修改课程"
v-model="open" // 控制对话框显示/隐藏的双向绑定变量
width="500px" // 对话框宽度
append-to-body // 将对话框插入到body元素下,避免父容器样式影响
>
<!-- 课程信息表单 -->
<el-form
ref="courseRef" // 表单引用,用于调用表单校验等方法
:model="form" // 绑定的表单数据对象,存储课程相关字段
:rules="rules" // 表单校验规则,定义各字段的验证逻辑
label-width="80px" // 表单标签宽度
>
<!-- 课程编码输入项 -->
<el-form-item label="课程编码" prop="code"> // label显示文本,prop关联form.code及对应校验规则
<el-input v-model="form.code" placeholder="请输入课程编码" /> // 双向绑定课程编码字段
</el-form-item>
<el-form-item label="课程学科" prop="subject">...</el-form-item> <!-- 课程学科输入项,prop关联form.subject -->
<el-form-item label="课程名称" prop="name">...</el-form-item> <!-- 课程名称输入项,prop关联form.name -->
<el-form-item label="价格" prop="price">...</el-form-item> <!-- 价格输入项,prop关联form.price -->
<el-form-item label="适用人群" prop="applicablePerson">...</el-form-item> <!-- 适用人群输入项,prop关联form.applicablePerson -->
<el-form-item label="课程介绍" prop="info">...</el-form-item> <!-- 课程介绍输入项,prop关联form.info -->
</el-form>
<!-- 对话框底部区域(自定义插槽) -->
<template #footer>
<div class="dialog-footer"> <!-- 底部按钮容器,通常用于放置操作按钮 -->
<!-- 确定按钮:点击触发表单提交逻辑 -->
<el-button type="primary" @click="submitForm">确定</el-button>
<!-- 取消按钮:点击触发关闭对话框等逻辑 -->
<el-button @click="cancel">取消</el-button>
</div>
</template>
</el-dialog>
②JavaScript
// 导入课程相关的API接口函数,分别用于获取课程列表、获取单个课程详情、删除课程、添加课程和更新课程
import { listCourse, getCourse, delCourse, addCourse, updateCourse } from "@/api/course/course";
// 获取当前组件实例的代理对象,用于在setup中访问组件的属性和方法(类似Vue2中的this)
const { proxy } = getCurrentInstance();
// 响应式变量定义
const courseList = ref([]); // 存储课程列表数据
const open = ref(false); // 控制弹窗(如新增/编辑课程弹窗)的显示与隐藏
const loading = ref(true); // 加载状态标识,用于显示加载动画
const showSearch = ref(true); // 控制搜索区域的显示与隐藏
const ids = ref([]); // 存储选中的课程ID数组,用于批量操作
const single = ref(true); // 控制是否允许单选(可能用于表格选择功能)
const multiple = ref(true); // 控制是否允许多选(可能用于表格选择功能)
const total = ref(0); // 存储课程总数,用于分页展示
const title = ref(""); // 弹窗标题(如"新增课程"或"编辑课程")
// 响应式对象,包含表单数据、查询参数和表单验证规则
const data = reactive({
form: {}, // 存储新增/编辑课程的表单数据
queryParams: { // 存储课程列表的查询参数
pageNum: 1, // 当前页码
pageSize: 10, // 每页条数
code: null, // 课程编码查询条件
subject: null, // 课程学科查询条件
name: null, // 课程名称查询条件
applicablePerson: null, // 适用人群查询条件
},
rules: { // 表单验证规则,用于新增/编辑课程时的表单验证
code: [
{ required: true, message: "课程编码不能为空", trigger: "blur" } // 课程编码必填验证
],
subject: [
{ required: true, message: "课程学科不能为空", trigger: "blur" } // 课程学科必填验证
],
name: [
{ required: true, message: "课程名称不能为空", trigger: "blur" } // 课程名称必填验证
],
price: [
{ required: true, message: "价格不能为空", trigger: "blur" } // 价格必填验证
],
applicablePerson: [
{ required: true, message: "适用人群不能为空", trigger: "blur" } // 适用人群必填验证
],
info: [
{ required: true, message: "课程介绍不能为空", trigger: "blur" } // 课程介绍必填验证
],
}
});
// 将data对象中的属性转为ref类型,方便在模板中使用(保持响应式)
const { queryParams, form, rules } = toRefs(data);
/** 查询课程管理列表 */
function getList() {
loading.value = true;
listCourse(queryParams.value).then(response => {
courseList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
// 取消按钮
function cancel() {
open.value = false;
reset();
}
// 表单重置
function reset() {
form.value = {
id: null,
code: null,
subject: null,
name: null,
price: null,
applicablePerson: null,
info: null,
createTime: null,
updateTime: null
};
proxy.resetForm("courseRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加课程管理";
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const _id = row.id || ids.value
getCourse(_id).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改课程管理";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["courseRef"].validate(valid => {
if (valid) {
if (form.value.id != null) {
updateCourse(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addCourse(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const _ids = row.id || ids.value;
proxy.$modal.confirm('是否确认删除课程管理编号为"' + _ids + '"的数据项?').then(function() {
return delCourse(_ids);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download('course/course/export', {
...queryParams.value
}, `course_${new Date().getTime()}.xlsx`)
}
getList();
十二、后端源码分析
/**
* 查询课程管理列表
* 这是JavaDoc注释,用于描述当前方法的功能,便于团队协作和代码维护
*/
// Spring Security权限注解,方法执行前会先校验权限
// @ss是若依框架自定义的权限表达式前缀,对应SecurityUtils工具类
// hasPermi方法会检查当前登录用户是否拥有"course:course:list"这个权限标识
// 权限标识在若依的"菜单管理"中配置,通过角色-用户关联实现权限控制
@PreAuthorize("@ss.hasPermi('course:course:list')")
// Spring MVC注解,将HTTP GET请求映射到/list路径
// 结合控制器类上的@RequestMapping前缀,完整访问路径为/模块名/list
@GetMapping("/list")
// 方法返回值TableDataInfo是若依封装的表格数据对象,包含分页信息和数据列表
// 参数Course course由Spring MVC自动进行参数绑定,接收前端传递的查询条件
public TableDataInfo list(Course course) {
// 开启分页功能,调用的是BaseController中的方法
// 底层使用PageHelper分页插件,会解析前端传入的page(页码)和limit(每页条数)参数
// 通过ThreadLocal存储分页参数,后续MyBatis执行SQL时会自动添加LIMIT条件
startPage();
// 调用Service层方法查询课程列表,传入查询条件对象
// Service层会进一步调用Mapper接口,MyBatis会根据条件生成动态SQL
// 由于PageHelper已开启分页,这里查询的实际是当前页的数据
List<Course> list = courseService.selectCourseList(course);
// 封装查询结果为TableDataInfo对象并返回
// 底层会通过PageInfo获取总记录数,设置到TableDataInfo的total属性中
// 返回的数据结构包含code状态码、msg提示信息、rows数据列表和total总条数
return getDataTable(list);
}
对于courseService中的selectCourseList方法,执行的是分页查询的操作,其底层逻辑为:
①BaseEntity
/**
* BaseEntity 解析说明
*
* 一、类的基础定位
* BaseEntity 是一个基础实体类,实现 Serializable 接口(支持序列化,用于网络传输、持久化等场景)
* 通常被业务实体类继承,用于抽取公共字段,避免重复定义
*/
public class BaseEntity implements Serializable {
/**
* 存储搜索条件
* 注解 @JsonIgnore 表示序列化(转JSON)时忽略该字段,避免暴露给前端
*/
@JsonIgnore
private String searchValue;
/**
* 记录数据创建者(如用户ID或用户名)
*/
private String createBy;
/**
* 记录创建时间
* 注解 @JsonFormat 指定 JSON 序列化/反序列化时的日期格式(yyyy-MM-dd HH:mm:ss)
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 记录数据更新者(如用户ID或用户名)
*/
private String updateBy;
/**
* 记录更新时间
* 注解 @JsonFormat 指定 JSON 序列化/反序列化时的日期格式(yyyy-MM-dd HH:mm:ss)
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/**
* 存储备注信息(业务自定义说明)
*/
private String remark;
/**
* 存储动态请求参数(如分页、排序条件)
* 注解 @JsonInclude(NON_EMPTY) 表示仅当Map非空时才序列化到JSON,避免空字段冗余
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private Map<String, Object> params;
/**
* 三、设计思路与价值
* 1. 公共字段复用:
* 将创建者、创建时间、更新者、更新时间等通用字段抽取到基类,业务实体(如User、Order)继承后直接复用,减少代码冗余
*
* 2. JSON 序列化控制:
* - @JsonIgnore:隐藏敏感/临时字段(如searchValue仅用于接收前端参数,无需返回)
* - @JsonFormat:统一日期格式,避免前端解析混乱
* - @JsonInclude(NON_EMPTY):精简JSON输出,空数据不序列化,提升传输效率
*
* 3. 扩展性:
* params为Map类型,支持灵活传递动态参数(如分页参数pageNum、pageSize),无需为每个业务定义固定字段
*/
}
十三、权限注解


十四、前后端交互流程
// 创建axios实例
const service =axios.create({
// axios中请求配置有baseURL选项,表示请求URL公共部分
baseURL :import.meta.env.VITE_APP_BASE_API,
// 超时
timeout:10000
})
- .env.development(开发环境)
- .env.production(生产环境)
- .env.staging(测试环境)
// request拦截器:用于在请求发送前对请求配置进行处理
service.interceptors.request.use(config => {
// 判断是否需要设置token(默认需要,除非显式指定isToken为false)
// 从请求头中获取isToken配置,若未配置则默认视为需要token
const isToken = (config.headers || {}).isToken === false;
// 判断是否需要防止数据重复提交(默认需要,除非显式指定repeatSubmit为false)
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false;
// 如果存在token且当前请求需要携带token,则在请求头中添加Authorization
if (getToken() && !isToken) {
// 按照Bearer Token规范,在token前添加"Bearer "前缀
config.headers['Authorization'] = 'Bearer ' + getToken();
// 注:实际项目中可根据后端要求调整token格式和请求头字段
}
// 处理GET请求的参数:将params参数转换为URL查询字符串
if (config.method === 'get' && config.params) {
// 调用tansParams函数(自定义参数转换函数)将params转为key=value&...格式
let url = config.url + '?' + tansParams(config.params);
// 去除最后一个多余的&符号(如果存在)
url = url.slice(0, -1);
// 清空params,避免重复携带参数
config.params = {};
// 更新请求URL为拼接后的完整URL
config.url = url;
}
// 处理防重复提交逻辑:仅对POST/PUT请求生效,且未禁用防重复提交时
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
// 构建当前请求的标识对象,用于后续对比
const requestObj = {
url: config.url, // 请求地址
// 将请求数据转为字符串(确保对象类型的数据可比较)
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
time: new Date().getTime() // 请求发送时间戳
};
// 计算当前请求数据的大小(字节)
const requestSize = Object.keys(JSON.stringify(requestObj)).length;
// 限制缓存的请求数据大小为5M(防止占用过多内存)
const limitSize = 5 * 1024 * 1024;
// 如果请求数据超过5M,不进行防重复提交验证(避免缓存过大)
if (requestSize >= limitSize) {
console.warn(`[${config.url}]: 请求数据大小超出允许的5M限制,无法进行防重复提交验证。`);
return config;
}
// 从sessionStorage中获取上一次的请求缓存(通过自定义cache工具)
const sessionObj = cache.session.getJSON('sessionObj');
// 如果缓存中没有历史请求记录,直接将当前请求存入缓存
if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
cache.session.setJSON('sessionObj', requestObj);
} else {
// 提取历史请求的关键信息
const s_url = sessionObj.url; // 历史请求地址
const s_data = sessionObj.data; // 历史请求数据
const s_time = sessionObj.time; // 历史请求时间
const interval = 1000; // 重复提交判断间隔(1秒内视为重复)
// 判断是否为重复提交:地址相同 + 数据相同 + 时间间隔小于1秒
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
const message = '数据正在处理,请勿重复提交';
console.warn(`[${s_url}]: ` + message);
// 抛出错误阻止请求发送,由业务代码捕获处理
return Promise.reject(new Error(message));
} else {
// 不是重复提交,更新缓存为当前请求
cache.session.setJSON('sessionObj', requestObj);
}
}
}
// 返回处理后的配置,继续发送请求
return config;
}, error => {
// 请求拦截器错误处理:打印错误信息并返回错误Promise
console.log(error);
return Promise.reject(error);
});
// 响应拦截器
service.interceptors.response.use(res => {
// 未设置状态码则默认成功状态
const code = res.data.code || 200;
// 获取错误信息
const msg = errorCode[code] || res.data.msg || errorCode['default']
// 二进制数据则直接返回
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
return res.data
}
if (code === 401) {
if (!isRelogin.show) {
isRelogin.show = true;
MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
isRelogin.show = false;
store.dispatch('LogOut').then(() => {
location.href = '/index';
})
}).catch(() => {
isRelogin.show = false;
});
}
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
Message({ message: msg, type: 'error' })
return Promise.reject(new Error(msg))
} else if (code === 601) {
Message({ message: msg, type: 'warning' })
return Promise.reject('error')
} else if (code !== 200) {
Notification.error({ title: msg })
return Promise.reject('error')
} else {
return res.data
}
},
error => {
console.log('err' + error)
let { message } = error;
if (message == "Network Error") {
message = "后端接口连接异常";
} else if (message.includes("timeout")) {
message = "系统接口请求超时";
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常";
}
Message({ message: message, type: 'error', duration: 5 * 1000 })
return Promise.reject(error)
}
)

十五、新增模块
①新增模块
②在新增模块的xml文件中添加
<dependencies>
<dependency>
<groupId>com.RB</groupId>
<artifactId>RB-framework</artifactId>
</dependency>
</dependencies>
③在父工程中进行版本锁定
<dependency>
<groupId>com.RB</groupId>
<artifactId>RB-music</artifactId>
<version>${RB.version}</version>
</dependency>
④在admin中添加
<dependency>
<groupId>com.RB</groupId>
<artifactId>RB-music</artifactId>
</dependency>
更多推荐








浏览器自动下载导出.zip文件











所有评论(0)